Merge lp:~dobey/ubuntuone-control-panel/update-4-2 into lp:ubuntuone-control-panel/stable-4-2
- update-4-2
- Merge into stable-4-2
Status: | Merged |
---|---|
Merged at revision: | 377 |
Proposed branch: | lp:~dobey/ubuntuone-control-panel/update-4-2 |
Merge into: | lp:ubuntuone-control-panel/stable-4-2 |
Diff against target: |
1230 lines (+763/-157) 13 files modified
bin/ubuntuone-updater (+184/-0) setup.py (+1/-1) ubuntuone/controlpanel/__init__.py (+0/-1) ubuntuone/controlpanel/gui/__init__.py (+8/-10) ubuntuone/controlpanel/gui/qt/gui.py (+1/-1) ubuntuone/controlpanel/gui/qt/main/__init__.py (+3/-1) ubuntuone/controlpanel/utils/__init__.py (+5/-3) ubuntuone/controlpanel/utils/common.py (+128/-0) ubuntuone/controlpanel/utils/darwin.py (+59/-8) ubuntuone/controlpanel/utils/tests/test_common.py (+233/-0) ubuntuone/controlpanel/utils/tests/test_darwin.py (+105/-16) ubuntuone/controlpanel/utils/tests/test_windows.py (+22/-79) ubuntuone/controlpanel/utils/windows.py (+14/-37) |
To merge this branch: | bzr merge lp:~dobey/ubuntuone-control-panel/update-4-2 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Brian Curtin (community) | Approve | ||
Review via email: mp+142744@code.launchpad.net |
Commit message
[Mike McCracken]
- Remove a debug print statement in the tests that snuck through.
- Use new SSO API to get platform-
- Add u1 folder to OS X Finder favorites sidebar on first launch.
[Brian Curtin]
- Add common updater script for mac and windows. (LP: #1087262)
Description of the change
Brian Curtin (brian.curtin) : | # |
Ubuntu One Auto Pilot (otto-pilot) wrote : | # |
Ubuntu One Auto Pilot (otto-pilot) wrote : | # |
The attempt to merge lp:~dobey/ubuntuone-control-panel/update-4-2 into lp:ubuntuone-control-panel/stable-4-2 failed. Below is the output from the failed tests.
*** Running DBus test suite ***
ubuntuone.
BaseTestCase
runTest ... [OK]
DBusServiceMa
test_
test_
DBusServiceTe
test_
test_
test_
test_
test_
test_
test_
test_
FileSyncTestCase
test_
test_
test_
test_
test_
test_
test_
test_
test_
test_
test_
test_
OperationsAut
test_
test_
test_
test_
test_
test_
test_
test_
test_
test_
test_
test_
t...
- 377. By dobey
-
[Mike McCracken]
- Remove a debug print statement in the tests that snuck through.
- Use new SSO API to get platform-appropriate translation function. (LP: 1074116)
- Add u1 folder to OS X Finder favorites sidebar on first launch.[Brian Curtin]
- Add common updater script for mac and windows. (LP: #1087262)
Preview Diff
1 | === added file 'bin/ubuntuone-updater' |
2 | --- bin/ubuntuone-updater 1970-01-01 00:00:00 +0000 |
3 | +++ bin/ubuntuone-updater 2013-01-10 18:07:21 +0000 |
4 | @@ -0,0 +1,184 @@ |
5 | +#!/usr/bin/python |
6 | +# -*- coding: utf-8 -*- |
7 | +# |
8 | +# Copyright 2012 Canonical Ltd. |
9 | +# |
10 | +# This program is free software: you can redistribute it and/or modify it |
11 | +# under the terms of the GNU General Public License version 3, as published |
12 | +# by the Free Software Foundation. |
13 | +# |
14 | +# This program is distributed in the hope that it will be useful, but |
15 | +# WITHOUT ANY WARRANTY; without even the implied warranties of |
16 | +# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
17 | +# PURPOSE. See the GNU General Public License for more details. |
18 | +# |
19 | +# You should have received a copy of the GNU General Public License along |
20 | +# with this program. If not, see <http://www.gnu.org/licenses/>. |
21 | + |
22 | +"""A script to check the website for new versions of Ubuntu One.""" |
23 | + |
24 | +from __future__ import print_function |
25 | + |
26 | +try: |
27 | + from urllib.request import urlopen, URLError |
28 | + from urllib.parse import urljoin |
29 | +except ImportError: |
30 | + from urllib2 import urlopen, URLError |
31 | + from urlparse import urljoin |
32 | + |
33 | +import argparse |
34 | +import hashlib |
35 | +import json |
36 | +import os |
37 | +import subprocess |
38 | +import sys |
39 | +import tempfile |
40 | + |
41 | +from dirspec.utils import get_program_path |
42 | + |
43 | + |
44 | +U1SDTOOL_EXECUTABLE = 'u1sdtool' |
45 | +DARWIN_APP_NAMES = {U1SDTOOL_EXECUTABLE: 'U1SDTool.app'} |
46 | + |
47 | + |
48 | +if sys.platform == "darwin": |
49 | + from Cocoa import NSRunningApplication, NSLog |
50 | + # IDs to terminate: Leave syncdaemon off this list, it is |
51 | + # terminated separately. |
52 | + BUNDLE_IDS = ["com.ubuntu.sso.login-qt", |
53 | + "com.ubuntu.sso.ssl-cert", |
54 | + "com.ubuntu.sso.login", |
55 | + "com.ubuntu.one.proxy-tunnel", |
56 | + "com.ubuntu.one.u1sdtool", |
57 | + "com.ubuntu.one.updater", |
58 | + "com.ubuntu.one.controlpanel", |
59 | + "com.ubuntu.one.menu"] |
60 | + |
61 | + |
62 | +def _do_download(url): |
63 | + """Download a URL and return the data it contains.""" |
64 | + resource = urlopen(url) |
65 | + if resource: |
66 | + data = resource.read() |
67 | + return data |
68 | + |
69 | + |
70 | +def _save_download(url, checksum): |
71 | + """Given URL data, save it to a file and return the file name. |
72 | + |
73 | + The resource is saved to a file which is the responsibility of callers |
74 | + to cleanup. It was created with tempfile.mkstemp.""" |
75 | + data = _do_download(url) |
76 | + |
77 | + md5 = hashlib.md5() |
78 | + md5.update(data) |
79 | + if checksum != md5.hexdigest(): |
80 | + raise Exception("Checksum mismatch") |
81 | + |
82 | + fd, name = tempfile.mkstemp() |
83 | + with os.fdopen(fd, "wb") as fobj: |
84 | + fobj.write(data) |
85 | + |
86 | + return name |
87 | + |
88 | + |
89 | +def run_install(url, checksum): |
90 | + try: |
91 | + args = [_save_download(url, checksum)] |
92 | + if sys.platform == 'darwin': |
93 | + args.insert(0, 'open') |
94 | + subprocess.Popen(args) |
95 | + except Exception as exc: |
96 | + print("Unable to install {}: {}".format(url, exc)) |
97 | + return False |
98 | + return True |
99 | + |
100 | + |
101 | +def check(args): |
102 | + """Check a URL and return True if a new version is available.""" |
103 | + error = (False, "", "") # Default to no new release. |
104 | + |
105 | + try: |
106 | + data = _do_download(args.url) |
107 | + except URLError as err: |
108 | + print("Download failed: {}".format(err)) |
109 | + return error |
110 | + |
111 | + try: |
112 | + info = json.loads(data) |
113 | + available = info[args.platform][args.release] |
114 | + avail_ver = available["version"] |
115 | + upgrade_available = avail_ver > args.current |
116 | + if upgrade_available: |
117 | + msg = "A new {} version is available at {}." |
118 | + print(msg.format(args.release, available["url"])) |
119 | + elif avail_ver == args.current: |
120 | + print("Version {} is the latest {}.".format(args.current, |
121 | + args.release)) |
122 | + else: |
123 | + print("Warning: installed version {} newer than advertised" |
124 | + " available version {} somehow.".format(args.current, |
125 | + avail_ver)) |
126 | + |
127 | + except Exception as exc: |
128 | + # Catch everything here. |
129 | + # KeyError is most likely, but we can't let this take us down. |
130 | + print("Exception while reading {}:".format(args.url), |
131 | + exc.__class__, exc.message) |
132 | + return error |
133 | + |
134 | + return upgrade_available, available["url"], available["checksum"] |
135 | + |
136 | + |
137 | +def kill_running_processes(): |
138 | + """Kill any running u1 processes.""" |
139 | + if sys.platform != "darwin": |
140 | + return |
141 | + NSLog("in kill") |
142 | + |
143 | + try: |
144 | + u1sdtoolpath = get_program_path(U1SDTOOL_EXECUTABLE, |
145 | + app_names=DARWIN_APP_NAMES) |
146 | + |
147 | + out = subprocess.check_output([u1sdtoolpath, '-q']) |
148 | + NSLog("u1sdtool said: {}".format(out)) |
149 | + except Exception as e: |
150 | + NSLog("exception running {} -q: {}".format(u1sdtoolpath, e)) |
151 | + |
152 | + for id in BUNDLE_IDS: |
153 | + NSRA = NSRunningApplication |
154 | + apps = NSRA.runningApplicationsWithBundleIdentifier_(id) |
155 | + NSLog("id: {} apps: {}".format(id, apps)) |
156 | + |
157 | + for app in apps: |
158 | + app.terminate() |
159 | + |
160 | + |
161 | +def main(*args): |
162 | + """Return 1 if the action was successful, 0 if not. |
163 | + |
164 | + The default option is to check that an update is available. |
165 | + Adding the --install option will download and run |
166 | + the update if available.""" |
167 | + parser = argparse.ArgumentParser() |
168 | + parser.add_argument("--install", action="store_true") |
169 | + parser.add_argument("--platform", type=str, default=sys.platform) |
170 | + parser.add_argument("--release", type=str, required=True) |
171 | + parser.add_argument("--current", type=int, required=True) |
172 | + parser.add_argument("--url", type=str, required=True) |
173 | + |
174 | + args = parser.parse_args() |
175 | + |
176 | + new_available, file, checksum = check(args) |
177 | + if not args.install: |
178 | + return 1 if new_available else 0 |
179 | + |
180 | + if args.install and new_available: |
181 | + installer = urljoin(args.url, file) |
182 | + print("Downloading and installing", installer) |
183 | + kill_running_processes() |
184 | + return 1 if run_install(installer, checksum) else 0 |
185 | + |
186 | + |
187 | +if __name__ == "__main__": |
188 | + sys.exit(main(sys.argv[:])) |
189 | |
190 | === modified file 'setup.py' |
191 | --- setup.py 2012-12-05 22:58:30 +0000 |
192 | +++ setup.py 2013-01-10 18:07:21 +0000 |
193 | @@ -193,7 +193,7 @@ |
194 | |
195 | DistUtilsExtra.auto.setup( |
196 | name='ubuntuone-control-panel', |
197 | - version='4.1', |
198 | + version='4.1.0', |
199 | license='GPL v3', |
200 | author='Natalia Bidart', |
201 | author_email='natalia.bidart@canonical.com', |
202 | |
203 | === modified file 'ubuntuone/controlpanel/__init__.py' |
204 | --- ubuntuone/controlpanel/__init__.py 2011-09-06 17:21:56 +0000 |
205 | +++ ubuntuone/controlpanel/__init__.py 2013-01-10 18:07:21 +0000 |
206 | @@ -30,4 +30,3 @@ |
207 | DBUS_PREFERENCES_IFACE = "com.ubuntuone.controlpanel.Preferences" |
208 | |
209 | WEBSERVICE_BASE_URL = u"https://one.ubuntu.com/api/" |
210 | -TRANSLATION_DOMAIN = 'ubuntuone-control-panel' |
211 | |
212 | === modified file 'ubuntuone/controlpanel/gui/__init__.py' |
213 | --- ubuntuone/controlpanel/gui/__init__.py 2012-11-02 13:10:20 +0000 |
214 | +++ ubuntuone/controlpanel/gui/__init__.py 2013-01-10 18:07:21 +0000 |
215 | @@ -16,23 +16,21 @@ |
216 | |
217 | """The control panel UI for Ubuntu One.""" |
218 | |
219 | -import gettext |
220 | -import sys |
221 | +import os |
222 | |
223 | # pylint: disable=W0611 |
224 | from ubuntuone.clientdefs import APP_NAME |
225 | # pylint: enable=W0611 |
226 | |
227 | -from ubuntuone.controlpanel import TRANSLATION_DOMAIN |
228 | +from ubuntu_sso.utils.translation import get_gettext |
229 | + |
230 | from ubuntuone.controlpanel.backend import UBUNTUONE_LINK |
231 | |
232 | - |
233 | -TRANSLATION = gettext.translation(TRANSLATION_DOMAIN, fallback=True) |
234 | -if sys.version_info < (3,): |
235 | - _ = TRANSLATION.ugettext |
236 | -else: |
237 | - _ = TRANSLATION.gettext |
238 | - |
239 | +source_path = os.path.join(os.path.dirname(__file__), |
240 | + os.path.pardir, os.path.pardir, |
241 | + os.path.pardir, 'build', 'mo') |
242 | +_ = get_gettext('ubuntuone-control-panel', |
243 | + fallback_path=os.path.abspath(source_path)) |
244 | |
245 | ERROR_COLOR = u'red' |
246 | KILOBYTES = 1024 |
247 | |
248 | === modified file 'ubuntuone/controlpanel/gui/qt/gui.py' |
249 | --- ubuntuone/controlpanel/gui/qt/gui.py 2012-11-01 19:33:57 +0000 |
250 | +++ ubuntuone/controlpanel/gui/qt/gui.py 2013-01-10 18:07:21 +0000 |
251 | @@ -123,7 +123,7 @@ |
252 | logger.info('Performing auto-update.') |
253 | utils.perform_update() |
254 | else: |
255 | - logger.info('User do not want to update.') |
256 | + logger.info('User does not want to update.') |
257 | |
258 | |
259 | def start(close_callback, minimized=False, with_icon=False, installer=False): |
260 | |
261 | === modified file 'ubuntuone/controlpanel/gui/qt/main/__init__.py' |
262 | --- ubuntuone/controlpanel/gui/qt/main/__init__.py 2012-11-30 18:06:22 +0000 |
263 | +++ ubuntuone/controlpanel/gui/qt/main/__init__.py 2013-01-10 18:07:21 +0000 |
264 | @@ -50,7 +50,8 @@ |
265 | |
266 | # pylint: enable=C0103 |
267 | |
268 | -from ubuntuone.controlpanel.utils import install_config_and_daemons |
269 | +from ubuntuone.controlpanel.utils import (install_config_and_daemons, |
270 | + add_u1_folder_to_favorites) |
271 | |
272 | |
273 | def parser_options(): |
274 | @@ -136,6 +137,7 @@ |
275 | app.setStyleSheet('\n'.join(data)) |
276 | |
277 | install_config_and_daemons() |
278 | + add_u1_folder_to_favorites() |
279 | |
280 | if sys.platform == 'darwin': |
281 | with_icon = False |
282 | |
283 | === modified file 'ubuntuone/controlpanel/utils/__init__.py' |
284 | --- ubuntuone/controlpanel/utils/__init__.py 2012-08-03 23:36:46 +0000 |
285 | +++ ubuntuone/controlpanel/utils/__init__.py 2013-01-10 18:07:21 +0000 |
286 | @@ -21,7 +21,6 @@ |
287 | |
288 | from ubuntuone.controlpanel.logger import setup_logging |
289 | |
290 | - |
291 | logger = setup_logging('utils') |
292 | |
293 | DATA_SUFFIX = 'data' |
294 | @@ -38,6 +37,7 @@ |
295 | if sys.platform == 'win32': |
296 | from ubuntuone.controlpanel.utils import windows |
297 | add_to_autostart = windows.add_to_autostart |
298 | + add_u1_folder_to_favorites = no_op |
299 | are_updates_present = windows.are_updates_present |
300 | default_folders = windows.default_folders |
301 | install_config_and_daemons = no_op |
302 | @@ -46,14 +46,16 @@ |
303 | elif sys.platform == 'darwin': |
304 | from ubuntuone.controlpanel.utils import darwin |
305 | add_to_autostart = no_op |
306 | - are_updates_present = no_op |
307 | + add_u1_folder_to_favorites = darwin.add_u1_folder_to_favorites |
308 | + are_updates_present = darwin.are_updates_present |
309 | default_folders = darwin.default_folders |
310 | install_config_and_daemons = darwin.install_config_and_daemons |
311 | - perform_update = no_op |
312 | + perform_update = darwin.perform_update |
313 | uninstall_application = no_op |
314 | else: |
315 | from ubuntuone.controlpanel.utils import linux |
316 | add_to_autostart = no_op |
317 | + add_u1_folder_to_favorites = no_op |
318 | are_updates_present = no_op |
319 | default_folders = linux.default_folders |
320 | install_config_and_daemons = no_op |
321 | |
322 | === added file 'ubuntuone/controlpanel/utils/common.py' |
323 | --- ubuntuone/controlpanel/utils/common.py 1970-01-01 00:00:00 +0000 |
324 | +++ ubuntuone/controlpanel/utils/common.py 2013-01-10 18:07:21 +0000 |
325 | @@ -0,0 +1,128 @@ |
326 | +# -*- coding: utf-8 -*- |
327 | +# |
328 | +# Copyright 2012 Canonical Ltd. |
329 | +# |
330 | +# This program is free software: you can redistribute it and/or modify it |
331 | +# under the terms of the GNU General Public License version 3, as published |
332 | +# by the Free Software Foundation. |
333 | +# |
334 | +# This program is distributed in the hope that it will be useful, but |
335 | +# WITHOUT ANY WARRANTY; without even the implied warranties of |
336 | +# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
337 | +# PURPOSE. See the GNU General Public License for more details. |
338 | +# |
339 | +# You should have received a copy of the GNU General Public License along |
340 | +# with this program. If not, see <http://www.gnu.org/licenses/>. |
341 | + |
342 | +"""Platform - independent support code for utils.""" |
343 | + |
344 | +import os |
345 | +import sys |
346 | + |
347 | +try: |
348 | + from configparser import (SafeConfigParser, NoSectionError, NoOptionError) |
349 | +except ImportError: |
350 | + from ConfigParser import (SafeConfigParser, NoSectionError, NoOptionError) |
351 | + |
352 | +from twisted.internet import defer |
353 | +from twisted.internet.utils import getProcessValue |
354 | +from twisted.python import procutils |
355 | + |
356 | +from dirspec.basedir import load_config_paths |
357 | +from dirspec.utils import get_program_path |
358 | + |
359 | +from ubuntuone.controlpanel.utils import logger |
360 | + |
361 | +UPDATE_BIN_NAME = 'ubuntuone-updater' |
362 | +UPDATE_CONFIG_NAME = 'update.conf' |
363 | +DARWIN_APP_NAMES = {UPDATE_BIN_NAME: 'UbuntuOne Updater.app'} |
364 | + |
365 | + |
366 | +def get_bin_cmd(exe_name): |
367 | + """Return list of cmds for an exe from the control panel project.""" |
368 | + fallback_dir = os.path.join(os.path.dirname(__file__), |
369 | + os.pardir, os.pardir, os.pardir, |
370 | + "bin") |
371 | + |
372 | + cmd_args = [get_program_path(exe_name, |
373 | + fallback_dirs=[fallback_dir], |
374 | + app_names=DARWIN_APP_NAMES)] |
375 | + |
376 | + # procutils.which('python') returns python.exe on windows: |
377 | + if getattr(sys, 'frozen', None) is None: |
378 | + cmd_args.insert(0, procutils.which('python')[0]) |
379 | + |
380 | + return cmd_args |
381 | + |
382 | + |
383 | +def get_update_config(): |
384 | + """Read the update.conf file and return a triple of |
385 | + the URL, version, and whether updates should be checked.""" |
386 | + no_config = (None, None, None, False) |
387 | + url, version, channel, check = no_config |
388 | + |
389 | + files = [os.path.join(dir, UPDATE_CONFIG_NAME) |
390 | + for dir in load_config_paths("ubuntuone")] |
391 | + |
392 | + conf = SafeConfigParser() |
393 | + read_files = conf.read(files) |
394 | + |
395 | + if not read_files: |
396 | + logger.debug( |
397 | + "Unable to find an update.conf file - not checking for updates") |
398 | + return no_config |
399 | + |
400 | + try: |
401 | + url = conf.get("Update", "url") |
402 | + version = conf.get("Update", "version_id") |
403 | + channel = conf.get("Update", "channel") |
404 | + check = conf.getint("Update", "check_for_updates") |
405 | + except (NoSectionError, NoOptionError) as e: |
406 | + logger.debug("could not read update.conf - not checking for updates") |
407 | + logger.debug(" (exception was %r)" % e) |
408 | + return no_config |
409 | + |
410 | + return url, version, channel, check |
411 | + |
412 | + |
413 | +@defer.inlineCallbacks |
414 | +def call_updater(custom_call=None, install=False): |
415 | + """Call the Ubuntu One updater.""" |
416 | + result = False |
417 | + retcode = None |
418 | + try: |
419 | + updater_cmd = get_bin_cmd(UPDATE_BIN_NAME) |
420 | + except OSError, e: |
421 | + logger.debug("Could not find updater command: %r" % e) |
422 | + defer.returnValue(result) |
423 | + |
424 | + url, local_version, channel, should_check = get_update_config() |
425 | + |
426 | + if not should_check: |
427 | + logger.debug("ignoring update check") |
428 | + defer.returnValue(result) |
429 | + |
430 | + args = ["--url", url, |
431 | + "--current", str(local_version), |
432 | + "--release", channel] |
433 | + if install: |
434 | + args.append("--install") |
435 | + |
436 | + exe = updater_cmd[0] |
437 | + args = updater_cmd[1:] + args |
438 | + |
439 | + logger.debug("calling %s update process: %r args %r", |
440 | + "custom" if custom_call else "regular", |
441 | + exe, args) |
442 | + |
443 | + if custom_call: |
444 | + custom_call(exe, args) |
445 | + else: |
446 | + # updater returns 1 if available, zero if not |
447 | + retcode = yield getProcessValue(exe, args) |
448 | + result = retcode == 1 |
449 | + |
450 | + logger.debug('call_updater: %s, updater cmd: %r, return code: %r,' |
451 | + ' result: %r', "installing" if install else "checking", |
452 | + updater_cmd, retcode, result) |
453 | + defer.returnValue(result) |
454 | |
455 | === modified file 'ubuntuone/controlpanel/utils/darwin.py' |
456 | --- ubuntuone/controlpanel/utils/darwin.py 2012-11-29 20:15:08 +0000 |
457 | +++ ubuntuone/controlpanel/utils/darwin.py 2013-01-10 18:07:21 +0000 |
458 | @@ -20,6 +20,14 @@ |
459 | import shutil |
460 | import sys |
461 | |
462 | +from Cocoa import (NSURL, NSUserDefaults) |
463 | +from LaunchServices import ( |
464 | + kLSSharedFileListFavoriteItems, |
465 | + kLSSharedFileListItemBeforeFirst, |
466 | + LSSharedFileListCreate, |
467 | + LSSharedFileListInsertItemURL, |
468 | + LSSharedFileListItemRef) |
469 | + |
470 | from ctypes import ( |
471 | byref, |
472 | CDLL, |
473 | @@ -39,10 +47,15 @@ |
474 | |
475 | from dirspec.basedir import save_config_path |
476 | from ubuntuone.controlpanel.logger import setup_logging |
477 | +from ubuntuone.controlpanel.utils.common import call_updater |
478 | from ubuntuone.platform import expand_user |
479 | |
480 | logger = setup_logging('utils.darwin') |
481 | |
482 | +ADDED_TO_FINDER_SIDEBAR_ONCE = "ADDED_TO_FINDER_SIDEBAR_ONCE" |
483 | + |
484 | +LOGO_ICON = "ubuntuone_logo.png" |
485 | + |
486 | AUTOUPDATE_BIN_NAME = 'autoupdate-darwin' |
487 | UNINSTALL_BIN_NAME = 'uninstall-darwin' |
488 | |
489 | @@ -343,11 +356,37 @@ |
490 | # TODO |
491 | |
492 | |
493 | +def _get_userdefaults(): |
494 | + """Testable wrapper for NSUserDefaults""" |
495 | + # HACK: This is required to avoid trial complaining on tear down |
496 | + # that assigning to native selectors is not supported. |
497 | + return NSUserDefaults.standardUserDefaults() |
498 | + |
499 | + |
500 | +def add_u1_folder_to_favorites(): |
501 | + """Add the u1 folder to the favorites sidebar in Finder.""" |
502 | + sud = _get_userdefaults() |
503 | + if sud.boolForKey_(ADDED_TO_FINDER_SIDEBAR_ONCE): |
504 | + return |
505 | + else: |
506 | + sud.setBool_forKey_(True, ADDED_TO_FINDER_SIDEBAR_ONCE) |
507 | + |
508 | + u1_path = os.path.expanduser("~/Ubuntu%20One/") |
509 | + u1_url = NSURL.URLWithString_("file://localhost" + "%s" % u1_path) |
510 | + |
511 | + lst = LSSharedFileListCreate(None, |
512 | + kLSSharedFileListFavoriteItems, |
513 | + None) |
514 | + item = LSSharedFileListInsertItemURL(lst, kLSSharedFileListItemBeforeFirst, |
515 | + None, None, u1_url, {}, []) |
516 | + if not isinstance(item, LSSharedFileListItemRef): |
517 | + logger.debug("Error adding ~/Ubuntu One to finder favorites") |
518 | + |
519 | + |
520 | @defer.inlineCallbacks |
521 | def are_updates_present(): |
522 | """Return if there are updates for Ubuntu One.""" |
523 | - result = False |
524 | - # TODO |
525 | + result = yield call_updater(install=False) |
526 | defer.returnValue(result) |
527 | |
528 | |
529 | @@ -448,23 +487,35 @@ |
530 | |
531 | config_path = save_config_path('ubuntuone') |
532 | |
533 | - conf_filenames = ['syncdaemon.conf', |
534 | - 'logging.conf'] |
535 | - for conf_filename in conf_filenames: |
536 | + # Always copy missing files, and for update.conf, overwrite |
537 | + # existing file to reflect current version ID, but only if bundled |
538 | + # version is newer, so we can change the file for testing. |
539 | + conf_filenames = [('syncdaemon.conf', False), |
540 | + ('logging.conf', False), |
541 | + ('update.conf', True)] |
542 | + for conf_filename, overwrite_old in conf_filenames: |
543 | src_path = os.path.join(main_app_resources_dir, |
544 | conf_filename) |
545 | dest_path = os.path.join(config_path, |
546 | conf_filename) |
547 | - |
548 | + do_copy = False |
549 | if not os.path.exists(dest_path): |
550 | + do_copy = True |
551 | + else: |
552 | + src_mtime = os.stat(src_path).st_mtime |
553 | + dest_mtime = os.stat(dest_path).st_mtime |
554 | + if overwrite_old and src_mtime >= dest_mtime: |
555 | + do_copy = True |
556 | + |
557 | + if do_copy: |
558 | shutil.copyfile(src_path, dest_path) |
559 | |
560 | check_and_install_fsevents_daemon(main_app_dir) |
561 | |
562 | |
563 | def perform_update(): |
564 | - """Spawn the autoupdate process and call the stop function.""" |
565 | - # TODO |
566 | + """Spawn the autoupdate process, which will eventually kill us.""" |
567 | + call_updater(install=True) |
568 | |
569 | |
570 | def uninstall_application(): |
571 | |
572 | === added file 'ubuntuone/controlpanel/utils/tests/test_common.py' |
573 | --- ubuntuone/controlpanel/utils/tests/test_common.py 1970-01-01 00:00:00 +0000 |
574 | +++ ubuntuone/controlpanel/utils/tests/test_common.py 2013-01-10 18:07:21 +0000 |
575 | @@ -0,0 +1,233 @@ |
576 | +# -*- coding: utf-8 -*- |
577 | +# |
578 | +# Copyright 2012 Canonical Ltd. |
579 | +# |
580 | +# This program is free software: you can redistribute it and/or modify it |
581 | +# under the terms of the GNU General Public License version 3, as published |
582 | +# by the Free Software Foundation. |
583 | +# |
584 | +# This program is distributed in the hope that it will be useful, but |
585 | +# WITHOUT ANY WARRANTY; without even the implied warranties of |
586 | +# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
587 | +# PURPOSE. See the GNU General Public License for more details. |
588 | +# |
589 | +# You should have received a copy of the GNU General Public License along |
590 | +# with this program. If not, see <http://www.gnu.org/licenses/>. |
591 | + |
592 | +"""Tests for utility code that's common between darwin and windows.""" |
593 | + |
594 | +from twisted.internet import defer |
595 | + |
596 | +try: |
597 | + from configparser import SafeConfigParser |
598 | +except ImportError: |
599 | + from ConfigParser import SafeConfigParser |
600 | + |
601 | +from ubuntuone.controlpanel import utils |
602 | +from ubuntuone.controlpanel.tests import TestCase |
603 | +from ubuntuone.controlpanel.utils import common |
604 | +assert(common) |
605 | + |
606 | +UPDATE_KEY = 'Update' |
607 | +URL_KEY = 'url' |
608 | +TEST_URL = 'test-url' |
609 | +VERSION_ID_KEY = 'version_id' |
610 | +TEST_VERSION_ID = '100' |
611 | +CHANNEL_KEY = 'channel' |
612 | +TEST_CHANNEL = 'test-channel' |
613 | +CHECK_KEY = 'check_for_updates' |
614 | +TEST_CHECK = '1' |
615 | + |
616 | + |
617 | +class GetPathsTestCase(TestCase): |
618 | + """Test case for get_update_config and get_bin_cmd.""" |
619 | + |
620 | + TEST_EXE_NAME = 'test-exe' |
621 | + TEST_BIN_CMD_NAME = 'test-bin-cmd-name' |
622 | + TEST_PYTHON_BIN_NAME = 'test-python-bin-name' |
623 | + |
624 | + def _run_get_bin_cmd(self, frozen): |
625 | + """Helper func to test get_bin_cmd.""" |
626 | + self.patch(utils.common, "get_program_path", |
627 | + lambda x, **kwargs: self.TEST_BIN_CMD_NAME) |
628 | + self.patch(utils.common, '__file__', |
629 | + "fake/path/to/utils/common.py") |
630 | + return utils.common.get_bin_cmd(self.TEST_EXE_NAME) |
631 | + |
632 | + def test_get_bin_cmd_frozen(self): |
633 | + """Test that we append 'python' from procutils when frozen.""" |
634 | + self.patch(utils.common.procutils, "which", |
635 | + lambda x: [self.TEST_PYTHON_BIN_NAME]) |
636 | + rv = self._run_get_bin_cmd(True) |
637 | + self.assertEqual(rv, [self.TEST_PYTHON_BIN_NAME, |
638 | + self.TEST_BIN_CMD_NAME]) |
639 | + |
640 | + |
641 | +class GetUpdateConfigTestCase(TestCase): |
642 | + """Test reading the config file""" |
643 | + |
644 | + @defer.inlineCallbacks |
645 | + def setUp(self): |
646 | + yield super(GetUpdateConfigTestCase, self).setUp() |
647 | + |
648 | + self.blank_conf = SafeConfigParser() |
649 | + self.good_conf = SafeConfigParser() |
650 | + self.good_conf.add_section(UPDATE_KEY) |
651 | + self.good_conf.set(UPDATE_KEY, URL_KEY, TEST_URL) |
652 | + self.good_conf.set(UPDATE_KEY, VERSION_ID_KEY, |
653 | + TEST_VERSION_ID) |
654 | + self.good_conf.set(UPDATE_KEY, CHANNEL_KEY, |
655 | + TEST_CHANNEL) |
656 | + self.good_conf.set(UPDATE_KEY, CHECK_KEY, TEST_CHECK) |
657 | + |
658 | + self.patch(utils.common, 'load_config_paths', |
659 | + lambda x: 'test/confpath') |
660 | + |
661 | + def test_cant_read(self): |
662 | + """Test that we return no_config when we can't read the cfg""" |
663 | + rv = utils.common.get_update_config() |
664 | + self.assertEqual(rv, (None, None, None, False)) |
665 | + |
666 | + def test_read_bad_file(self): |
667 | + """Test that we return no_config when we read a bad cfg file""" |
668 | + self.patch(utils.common, "SafeConfigParser", |
669 | + lambda: self.blank_conf) |
670 | + |
671 | + self.patch(self.blank_conf, "read", lambda path: True) |
672 | + rv = utils.common.get_update_config() |
673 | + self.assertEqual(rv, (None, None, None, False)) |
674 | + |
675 | + def test_read_good_file(self): |
676 | + """test that we correctly read a good cfg file""" |
677 | + self.patch(utils.common, "SafeConfigParser", |
678 | + lambda: self.good_conf) |
679 | + |
680 | + self.patch(self.good_conf, "read", lambda path: True) |
681 | + rv = utils.common.get_update_config() |
682 | + self.assertEqual(rv, |
683 | + (TEST_URL, TEST_VERSION_ID, TEST_CHANNEL, 1)) |
684 | + |
685 | + |
686 | +class CallUpdaterTestCase(TestCase): |
687 | + """Test calling the updater.""" |
688 | + |
689 | + UPDATE_BIN_CMD = ['path/to/updater'] |
690 | + BUILDOUT_UPDATE_BIN_CMD = ['python', 'path/to/updater'] |
691 | + |
692 | + @defer.inlineCallbacks |
693 | + def setUp(self): |
694 | + """Set up common data""" |
695 | + yield super(CallUpdaterTestCase, self).setUp() |
696 | + |
697 | + self.getProcessValueArgs = [] |
698 | + self.custom_call_args = [] |
699 | + |
700 | + self.call_retval = 0 |
701 | + |
702 | + def fake_getProcessValue(exe, args): |
703 | + self.getProcessValueArgs.append((exe, args)) |
704 | + return self.call_retval |
705 | + |
706 | + self.patch(utils.common, 'getProcessValue', |
707 | + fake_getProcessValue) |
708 | + |
709 | + def fake_custom_call(self, exe, args): |
710 | + """Mock custom call""" |
711 | + self.custom_call_args.append((exe, args)) |
712 | + |
713 | + @defer.inlineCallbacks |
714 | + def _call_call_updater(self, should_check, custom_call, install, frozen): |
715 | + """Helper to test call_udpater""" |
716 | + |
717 | + self.patch(utils.common, 'get_update_config', |
718 | + lambda: (TEST_URL, TEST_VERSION_ID, TEST_CHANNEL, |
719 | + should_check)) |
720 | + |
721 | + self.patch(utils.common, 'get_bin_cmd', |
722 | + lambda x: self.UPDATE_BIN_CMD if frozen |
723 | + else self.BUILDOUT_UPDATE_BIN_CMD) |
724 | + |
725 | + rv = yield utils.common.call_updater(custom_call, install) |
726 | + defer.returnValue(rv) |
727 | + |
728 | + @defer.inlineCallbacks |
729 | + def test_do_not_check(self): |
730 | + """Test that we return False when config says don't check """ |
731 | + |
732 | + rv = yield self._call_call_updater(should_check=False, |
733 | + custom_call=None, |
734 | + install=False, |
735 | + frozen=False) |
736 | + self.assertEqual(rv, False) |
737 | + |
738 | + @defer.inlineCallbacks |
739 | + def test_no_updater_cmd(self): |
740 | + """Test that we return False when get_bin_cmd fails.""" |
741 | + def raise_in_get_bin_cmd(name): |
742 | + raise OSError() |
743 | + |
744 | + self.patch(utils.common, 'get_bin_cmd', raise_in_get_bin_cmd) |
745 | + rv = yield utils.common.call_updater() |
746 | + |
747 | + self.assertEqual(rv, False) |
748 | + |
749 | + @defer.inlineCallbacks |
750 | + def test_update_check_frozen_nocustom_noinstall(self): |
751 | + """Test update check when frozen.""" |
752 | + self.call_retval = 1 |
753 | + rv = yield self._call_call_updater(should_check=True, |
754 | + custom_call=None, |
755 | + install=False, |
756 | + frozen=True) |
757 | + self.assertEqual(rv, True) |
758 | + self.assertEqual(self.getProcessValueArgs, |
759 | + [(self.UPDATE_BIN_CMD[0], |
760 | + ['--url', TEST_URL, |
761 | + '--current', TEST_VERSION_ID, |
762 | + '--release', TEST_CHANNEL])]) |
763 | + |
764 | + @defer.inlineCallbacks |
765 | + def test_update_check_unfrozen_nocustom_noinstall(self): |
766 | + """Test update check when not frozen.""" |
767 | + self.call_retval = 1 |
768 | + rv = yield self._call_call_updater(should_check=True, |
769 | + custom_call=None, |
770 | + install=False, |
771 | + frozen=False) |
772 | + self.assertEqual(rv, True) |
773 | + self.assertEqual(self.getProcessValueArgs, |
774 | + [(self.BUILDOUT_UPDATE_BIN_CMD[0], |
775 | + [self.BUILDOUT_UPDATE_BIN_CMD[1], |
776 | + '--url', TEST_URL, |
777 | + '--current', TEST_VERSION_ID, |
778 | + '--release', TEST_CHANNEL])]) |
779 | + |
780 | + @defer.inlineCallbacks |
781 | + def test_update_check_nocustom_install(self): |
782 | + """Test that we send --install when install=True""" |
783 | + |
784 | + yield self._call_call_updater(should_check=True, |
785 | + custom_call=None, |
786 | + install=True, |
787 | + frozen=True) |
788 | + self.assertEqual(self.getProcessValueArgs, |
789 | + [(self.UPDATE_BIN_CMD[0], |
790 | + ['--url', TEST_URL, |
791 | + '--current', TEST_VERSION_ID, |
792 | + '--release', TEST_CHANNEL, |
793 | + '--install'])]) |
794 | + |
795 | + @defer.inlineCallbacks |
796 | + def test_update_check_custom_install(self): |
797 | + """Test that we send --install when install=True to the custom call""" |
798 | + |
799 | + yield self._call_call_updater(should_check=True, |
800 | + custom_call=self.fake_custom_call, |
801 | + install=True, |
802 | + frozen=True) |
803 | + self.assertEqual(self.custom_call_args, |
804 | + [(self.UPDATE_BIN_CMD[0], |
805 | + ['--url', TEST_URL, |
806 | + '--current', TEST_VERSION_ID, |
807 | + '--release', TEST_CHANNEL, |
808 | + '--install'])]) |
809 | |
810 | === modified file 'ubuntuone/controlpanel/utils/tests/test_darwin.py' |
811 | --- ubuntuone/controlpanel/utils/tests/test_darwin.py 2012-10-17 17:28:43 +0000 |
812 | +++ ubuntuone/controlpanel/utils/tests/test_darwin.py 2013-01-10 18:07:21 +0000 |
813 | @@ -19,7 +19,9 @@ |
814 | import os |
815 | import sys |
816 | |
817 | -from collections import defaultdict |
818 | +from Cocoa import NSURL |
819 | + |
820 | +from collections import defaultdict, namedtuple |
821 | from functools import partial |
822 | |
823 | from twisted.internet import defer |
824 | @@ -56,12 +58,28 @@ |
825 | class InstallConfigTestCase(TestCase): |
826 | """Test install_config_and_daemons.""" |
827 | |
828 | + APP_PATH = "/path/to/Main.app/" |
829 | + TARGET_PATH = "TARGET_PATH" |
830 | + |
831 | @defer.inlineCallbacks |
832 | def setUp(self): |
833 | """Set up multi-call checker.""" |
834 | yield super(InstallConfigTestCase, self).setUp() |
835 | self._called = [] |
836 | |
837 | + self.non_overwrite_args = [((os.path.join(self.APP_PATH, 'Contents', |
838 | + 'Resources', |
839 | + 'syncdaemon.conf'), |
840 | + os.path.join(self.TARGET_PATH, |
841 | + 'syncdaemon.conf')), {}), |
842 | + ((os.path.join(self.APP_PATH, 'Contents', |
843 | + 'Resources', 'logging.conf'), |
844 | + os.path.join(self.TARGET_PATH, |
845 | + 'logging.conf')), {})] |
846 | + self.overwrite_args = [((os.path.join(self.APP_PATH, 'Contents', |
847 | + 'Resources', 'update.conf'), |
848 | + os.path.join(self.TARGET_PATH, |
849 | + 'update.conf')), {})] |
850 | self.patch(utils.darwin, |
851 | 'check_and_install_fsevents_daemon', |
852 | lambda _: None) |
853 | @@ -78,34 +96,45 @@ |
854 | utils.install_config_and_daemons() |
855 | self.assertEqual(self._called, []) |
856 | |
857 | - def _test_copying_conf_files(self, exists): |
858 | + def _test_copying_conf_files(self, exists, src_mtime=0, dest_mtime=0): |
859 | """Call install_config_and_daemons, parameterize os.path.exists.""" |
860 | sys.frozen = 'macosx_app' |
861 | self.addCleanup(delattr, sys, 'frozen') |
862 | - self.patch(utils.darwin, 'save_config_path', lambda x: "TARGET_PATH") |
863 | - self.patch(utils.darwin, '__file__', "/path/to/Main.app/ignore") |
864 | + self.patch(utils.darwin, 'save_config_path', |
865 | + lambda x: self.TARGET_PATH) |
866 | + self.patch(utils.darwin, '__file__', |
867 | + os.path.join(self.APP_PATH, "ignore")) |
868 | self.patch(os.path, "exists", lambda x: exists) |
869 | self.patch(utils.darwin.shutil, 'copyfile', |
870 | self._set_called) |
871 | + |
872 | + def fake_stat(path): |
873 | + fakestat = namedtuple('fakestat', ['st_mtime']) |
874 | + if path.startswith(self.APP_PATH): |
875 | + return fakestat(src_mtime) |
876 | + else: |
877 | + return fakestat(dest_mtime) |
878 | + |
879 | + self.patch(utils.os, 'stat', fake_stat) |
880 | + |
881 | utils.install_config_and_daemons() |
882 | |
883 | - def test_copies_conf_files(self): |
884 | + def test_copies_conf_files_same(self): |
885 | """When frozen, we copy the conf files if they don't exist.""" |
886 | self._test_copying_conf_files(False) |
887 | - self.assertEqual(self._called, |
888 | - [(('/path/to/Main.app/Contents/' |
889 | - 'Resources/syncdaemon.conf', |
890 | - 'TARGET_PATH/syncdaemon.conf'), {}), |
891 | - (('/path/to/Main.app/Contents/' |
892 | - 'Resources/logging.conf', |
893 | - 'TARGET_PATH/logging.conf'), |
894 | - {})]) |
895 | + self.assertEqual(self._called, self.non_overwrite_args + |
896 | + self.overwrite_args) |
897 | |
898 | - def test_does_not_copy_conf_files(self): |
899 | - """When frozen, we do not copy the conf files if they do exist.""" |
900 | - self._test_copying_conf_files(True) |
901 | + def test_does_not_copy_conf_files_same(self): |
902 | + """frozen: do not copy any files that exist if their mtime is new.""" |
903 | + self._test_copying_conf_files(True, src_mtime=0, dest_mtime=1) |
904 | self.assertEqual(self._called, []) |
905 | |
906 | + def test_only_copy_update_exist_same(self): |
907 | + """frz: only copy update.conf if files exist but src mtime newer.""" |
908 | + self._test_copying_conf_files(True, src_mtime=1, dest_mtime=0) |
909 | + self.assertEqual(self._called, self.overwrite_args) |
910 | + |
911 | |
912 | class InstallDaemonTestCase(CallRecordingTestCase): |
913 | """Test fsevents daemon installation.""" |
914 | @@ -326,3 +355,63 @@ |
915 | """Paths should be bytes, not unicode.""" |
916 | is_bytes = [type(n) == type(b'') for n in self.folders] |
917 | self.assertNotIn(False, is_bytes) |
918 | + |
919 | + |
920 | +class MockStandardUserDefaults(object): |
921 | + """Fake user defaults""" |
922 | + |
923 | + def __init__(self, keyval): |
924 | + self.keyval = keyval |
925 | + self.setBool_args = [] |
926 | + |
927 | + def boolForKey_(self, key): |
928 | + return self.keyval |
929 | + |
930 | + def setBool_forKey_(self, bval, key): |
931 | + self.setBool_args.append((bval, key)) |
932 | + |
933 | + |
934 | +class AddU1FolderToFavoritesTestCase(CallRecordingTestCase): |
935 | + """Test adding folder to favorites.""" |
936 | + |
937 | + @defer.inlineCallbacks |
938 | + def setUp(self): |
939 | + yield super(AddU1FolderToFavoritesTestCase, self).setUp() |
940 | + self.path = "/Users/a/Ubuntu%20One" |
941 | + self.testurl = NSURL.URLWithString_("file://localhost" + |
942 | + self.path) |
943 | + |
944 | + self.patch(utils.darwin.os.path, "expanduser", |
945 | + lambda x: self.path) |
946 | + self.patch(utils.darwin, "LSSharedFileListCreate", |
947 | + lambda x, y, z: "fake-list") |
948 | + self.patch(utils.darwin, "kLSSharedFileListItemBeforeFirst", 1) |
949 | + self._patch_and_track(utils.darwin, [("LSSharedFileListInsertItemURL", |
950 | + None)]) |
951 | + |
952 | + def test_call_with_home_url_noflag(self): |
953 | + """Test adding correct URL when we haven't before.""" |
954 | + |
955 | + mock_sud = MockStandardUserDefaults(False) |
956 | + self.patch(utils.darwin, '_get_userdefaults', |
957 | + lambda: mock_sud) |
958 | + |
959 | + utils.darwin.add_u1_folder_to_favorites() |
960 | + self.assertEqual(mock_sud.setBool_args, |
961 | + [(True, utils.darwin.ADDED_TO_FINDER_SIDEBAR_ONCE)]) |
962 | + self.assertEqual(self._called['LSSharedFileListInsertItemURL'], |
963 | + [(("fake-list", 1, None, None, self.testurl, {}, []), |
964 | + {})]) |
965 | + |
966 | + def test_call_with_home_url_yesflag(self): |
967 | + """Test not re-adding URL when we've done it once before.""" |
968 | + |
969 | + mock_sud = MockStandardUserDefaults(True) |
970 | + self.patch(utils.darwin, '_get_userdefaults', |
971 | + lambda: mock_sud) |
972 | + |
973 | + utils.darwin.add_u1_folder_to_favorites() |
974 | + |
975 | + self.assertEqual(mock_sud.setBool_args, []) |
976 | + |
977 | + self.assertEqual(self._called['LSSharedFileListInsertItemURL'], []) |
978 | |
979 | === modified file 'ubuntuone/controlpanel/utils/tests/test_windows.py' |
980 | --- ubuntuone/controlpanel/utils/tests/test_windows.py 2012-05-16 14:01:27 +0000 |
981 | +++ ubuntuone/controlpanel/utils/tests/test_windows.py 2013-01-10 18:07:21 +0000 |
982 | @@ -23,7 +23,7 @@ |
983 | |
984 | from ubuntuone.controlpanel import utils |
985 | from ubuntuone.controlpanel.tests import TestCase |
986 | -from ubuntuone.devtools.testcases import skipIfJenkins |
987 | +from ubuntuone.devtools.testcases import skipIfJenkins, skipIf |
988 | |
989 | # let me use protected methods |
990 | # pylint: disable=W0212 |
991 | @@ -65,8 +65,6 @@ |
992 | """Prepare for the diff tests.""" |
993 | yield super(AutoupdaterTestCase, self).setUp() |
994 | self._base_path = r'path\to\exe' |
995 | - self.auto_update_path = os.path.join(self._base_path, |
996 | - utils.windows.AUTOUPDATE_EXE_NAME) |
997 | self.return_from_call = 0 |
998 | self.command = None |
999 | self.args = [] |
1000 | @@ -77,9 +75,11 @@ |
1001 | self.args = args |
1002 | return self.return_from_call |
1003 | |
1004 | - self.patch(utils.windows, 'getProcessValue', fake_execute_process) |
1005 | - self.patch(utils.windows, 'get_exe_path', |
1006 | + self.patch(utils.common, 'getProcessValue', fake_execute_process) |
1007 | + self.patch(utils.windows, 'get_bin_cmd', |
1008 | lambda exe_name: os.path.join(self._base_path, exe_name)) |
1009 | + self.patch(utils.common, 'get_update_config', |
1010 | + lambda: ("URL", "VERSION", "CHANNEL", "CHECK")) |
1011 | |
1012 | @defer.inlineCallbacks |
1013 | def test_are_updates_present_true(self): |
1014 | @@ -87,13 +87,15 @@ |
1015 | # the idea is simple, set the value to be returned from |
1016 | # the fake call, assert that we get true and also that |
1017 | # we did use the correct parameters. |
1018 | - self.return_from_call = 0 |
1019 | + self.return_from_call = 1 |
1020 | are_present = yield utils.are_updates_present() |
1021 | self.assertTrue(are_present, 'Updates should be present.') |
1022 | # lets assert that we did use the correct args |
1023 | - expected_args = ('--mode', 'unattended') |
1024 | + expected_args = [ |
1025 | + utils.common.get_bin_cmd(utils.common.UPDATE_BIN_NAME)[1], |
1026 | + '--url', 'URL', '--current', 'VERSION', |
1027 | + '--release', 'CHANNEL'] |
1028 | self.assertEqual(expected_args, self.args) |
1029 | - self.assertEqual(self.command, self.auto_update_path) |
1030 | |
1031 | @defer.inlineCallbacks |
1032 | def test_are_updates_present_false(self): |
1033 | @@ -103,16 +105,22 @@ |
1034 | are_present = yield utils.are_updates_present() |
1035 | self.assertFalse(are_present, 'Updates should NOT be present.') |
1036 | # lets assert that we did use the correct args |
1037 | - expected_args = ('--mode', 'unattended') |
1038 | + expected_args = [ |
1039 | + utils.common.get_bin_cmd(utils.common.UPDATE_BIN_NAME)[1], |
1040 | + '--url', 'URL', '--current', 'VERSION', |
1041 | + '--release', 'CHANNEL'] |
1042 | self.assertEqual(expected_args, self.args) |
1043 | - self.assertEqual(self.command, self.auto_update_path) |
1044 | |
1045 | def test_perform_update(self): |
1046 | """Test the method that performs the update.""" |
1047 | self.patch(utils.windows.win32api, 'ShellExecute', self._set_called) |
1048 | utils.perform_update() |
1049 | - args = (None, 'runas', self.auto_update_path, |
1050 | - '--unattendedmodeui none', '', 0) |
1051 | + args = [utils.common.get_bin_cmd(utils.common.UPDATE_BIN_NAME)[1], |
1052 | + '--url', 'URL', '--current', 'VERSION', |
1053 | + '--release', 'CHANNEL', '--install'] |
1054 | + args = (None, 'runas', |
1055 | + utils.common.get_bin_cmd(utils.common.UPDATE_BIN_NAME)[0], |
1056 | + ' '.join(args), '', 0) |
1057 | self.assertEqual(self._called, (args, {})) |
1058 | |
1059 | |
1060 | @@ -247,72 +255,7 @@ |
1061 | self.test_special_folders(names=('PERSONAL', 'MYMUSIC', 'MYPICTURES')) |
1062 | |
1063 | |
1064 | -class GetExePathTestCase(FrozenTestCase): |
1065 | - """Test the path calculator when sys is frozen.""" |
1066 | - |
1067 | - @defer.inlineCallbacks |
1068 | - def setUp(self): |
1069 | - """Set the different tests.""" |
1070 | - yield super(GetExePathTestCase, self).setUp() |
1071 | - self.called = [] |
1072 | - self.exists = True |
1073 | - |
1074 | - def fake_abspath(path): |
1075 | - """Fake os.path.abspath.""" |
1076 | - self.called.append('os.path.abspath') |
1077 | - return path |
1078 | - |
1079 | - def fake_dirname(path): |
1080 | - """Fake os.path.dirname.""" |
1081 | - self.called.append('os.path.dirname') |
1082 | - return path |
1083 | - |
1084 | - def fake_exists(path): |
1085 | - """Fake os.path.exists.""" |
1086 | - self.called.append('os.path.exists') |
1087 | - return self.exists |
1088 | - |
1089 | - # patch the os.path functions used |
1090 | - self.patch(utils.windows.os.path, 'abspath', fake_abspath) |
1091 | - self.patch(utils.windows.os.path, 'dirname', fake_dirname) |
1092 | - self.patch(utils.windows.os.path, 'exists', fake_exists) |
1093 | - |
1094 | - def test_get_exe_path(self): |
1095 | - """Test the method used to get the autoupdate.""" |
1096 | - path = utils.windows.get_exe_path(exe_name=SOME_EXE_NAME) |
1097 | - |
1098 | - self.assertEqual(os.path.join(self.executable, SOME_EXE_NAME), path) |
1099 | - |
1100 | - expected = ['os.path.abspath', 'os.path.dirname', 'os.path.dirname', |
1101 | - 'os.path.exists'] |
1102 | - self.assertEqual(expected, self.called) |
1103 | - |
1104 | - def test_get_exe_path_not_present(self): |
1105 | - """Test the method used to get the autoupdate.""" |
1106 | - self.exists = False |
1107 | - |
1108 | - # called method and assert that we have the correct result |
1109 | - path = utils.windows.get_exe_path(exe_name=SOME_EXE_NAME) |
1110 | - self.assertTrue(path is None) |
1111 | - |
1112 | - |
1113 | -class GetExePathNotFrozenTestCase(GetExePathTestCase): |
1114 | - """Test the path calculator when sys is not frozen.""" |
1115 | - |
1116 | - frozen = None |
1117 | - |
1118 | - def test_get_exe_path(self): |
1119 | - """Test the method used to get the autoupdate.""" |
1120 | - self.patch(utils.windows, '__file__', self.executable) |
1121 | - |
1122 | - path = utils.windows.get_exe_path(exe_name=SOME_EXE_NAME) |
1123 | - self.assertEqual(os.path.join(self.executable, SOME_EXE_NAME), path) |
1124 | - |
1125 | - expected = ['os.path.dirname', 'os.path.dirname', 'os.path.dirname', |
1126 | - 'os.path.exists'] |
1127 | - self.assertEqual(expected, self.called) |
1128 | - |
1129 | - |
1130 | +@skipIf(not getattr(sys, "frozen", False), "Only applicable when frozen") |
1131 | class UninstallApplicationTestCase(FrozenTestCase): |
1132 | """Test the uninstall_application helper when sys is frozen.""" |
1133 | |
1134 | @@ -327,7 +270,7 @@ |
1135 | utils.uninstall_application() |
1136 | |
1137 | exe_name = utils.windows.UNINSTALL_EXE_NAME |
1138 | - uninstall_path = utils.windows.get_exe_path(exe_name=exe_name) |
1139 | + uninstall_path = utils.common.get_bin_cmd(exe_name=exe_name)[0] |
1140 | self.assertEqual(self._called, |
1141 | ((None, '', uninstall_path, '--mode win32', '', 0), {})) |
1142 | |
1143 | |
1144 | === modified file 'ubuntuone/controlpanel/utils/windows.py' |
1145 | --- ubuntuone/controlpanel/utils/windows.py 2012-04-05 14:52:55 +0000 |
1146 | +++ ubuntuone/controlpanel/utils/windows.py 2013-01-10 18:07:21 +0000 |
1147 | @@ -27,32 +27,15 @@ |
1148 | from win32com.shell import shell, shellcon |
1149 | # pylint: enable=F0401 |
1150 | from twisted.internet import defer |
1151 | -from twisted.internet.utils import getProcessValue |
1152 | |
1153 | +from ubuntuone.controlpanel.utils.common import (call_updater, get_bin_cmd) |
1154 | from ubuntuone.controlpanel.logger import setup_logging |
1155 | |
1156 | logger = setup_logging('utils.windows') |
1157 | -AUTOUPDATE_EXE_NAME = 'autoupdate-windows.exe' |
1158 | AUTORUN_KEY = r"Software\Microsoft\Windows\CurrentVersion\Run" |
1159 | UNINSTALL_EXE_NAME = 'uninstall.exe' |
1160 | |
1161 | |
1162 | -def get_exe_path(exe_name): |
1163 | - """Return the path in which the autoupdate command is found.""" |
1164 | - if getattr(sys, 'frozen', False): |
1165 | - exec_path = os.path.abspath(sys.executable) |
1166 | - else: |
1167 | - exec_path = os.path.dirname(__file__) |
1168 | - |
1169 | - result = None |
1170 | - folder = os.path.dirname(os.path.dirname(exec_path)) |
1171 | - exe_path = os.path.join(folder, exe_name) |
1172 | - if os.path.exists(exe_path): |
1173 | - result = exe_path |
1174 | - |
1175 | - return result |
1176 | - |
1177 | - |
1178 | def add_to_autostart(): |
1179 | """Add syncdaemon to the session's autostart.""" |
1180 | if getattr(sys, "frozen", False): |
1181 | @@ -74,19 +57,15 @@ |
1182 | @defer.inlineCallbacks |
1183 | def are_updates_present(): |
1184 | """Return if there are updates for Ubuntu One.""" |
1185 | - result = False |
1186 | - retcode = None |
1187 | - update_path = get_exe_path(exe_name=AUTOUPDATE_EXE_NAME) |
1188 | - if update_path is not None: |
1189 | - # If there is an update present we will get 0, non-zero otherwise |
1190 | - retcode = yield getProcessValue(update_path, args=('--mode', |
1191 | - 'unattended'), path=os.path.dirname(update_path)) |
1192 | - result = retcode == 0 |
1193 | - logger.debug('are_updates_present: update path: %r, return code: %r,' |
1194 | - ' result: %r', update_path, retcode, result) |
1195 | + result = yield call_updater(install=False) |
1196 | defer.returnValue(result) |
1197 | |
1198 | |
1199 | +def call_elevated(exe, args): |
1200 | + """ShellExecute wrapper that uses 'runas' to elevate.""" |
1201 | + win32api.ShellExecute(None, "runas", exe, " ".join(args), "", 0) |
1202 | + |
1203 | + |
1204 | def default_folders(user_home=None): |
1205 | """Return a list of the folders to add by default.""" |
1206 | # as per http://msdn.microsoft.com/en-us/library/windows/desktop/bb762181, |
1207 | @@ -112,16 +91,14 @@ |
1208 | |
1209 | |
1210 | def perform_update(): |
1211 | - """Spawn the autoupdate process and call the stop function.""" |
1212 | - update_path = get_exe_path(exe_name=AUTOUPDATE_EXE_NAME) |
1213 | - if update_path is not None: |
1214 | - # lets call the updater with the commands that are required, |
1215 | - win32api.ShellExecute(None, 'runas', update_path, |
1216 | - '--unattendedmodeui none', '', 0) |
1217 | + """Spawn the autoupdate process, which will eventually kill us.""" |
1218 | + call_updater(call_elevated, install=True) |
1219 | |
1220 | |
1221 | def uninstall_application(): |
1222 | """Uninstall Ubuntu One.""" |
1223 | - uninstall_path = get_exe_path(exe_name=UNINSTALL_EXE_NAME) |
1224 | - if uninstall_path is not None: |
1225 | - win32api.ShellExecute(None, '', uninstall_path, '--mode win32', '', 0) |
1226 | + if getattr(sys, "frozen", False): |
1227 | + uninstall_path = get_bin_cmd(UNINSTALL_EXE_NAME)[0] |
1228 | + if uninstall_path is not None: |
1229 | + win32api.ShellExecute(None, '', uninstall_path, |
1230 | + '--mode win32', '', 0) |
The attempt to merge lp:~dobey/ubuntuone-control-panel/update-4-2 into lp:ubuntuone-control-panel/stable-4-2 failed. Below is the output from the failed tests.
*** Running DBus test suite *** controlpanel. dbustests. test_dbus_ service inTestCase dbus_service_ cant_register ... Control panel backend already running.
[OK] dbus_service_ main ... [OK] stCase cant_register_ twice ... [SKIPPED] dbus_busname_ created ... [OK] error_handler_ default ... [OK] error_handler_ with_exception ... [OK] error_handler_ with_failure ... [OK] error_handler_ with_non_ string_ dict ... [OK] error_handler_ with_string_ dict ... [OK] register_ service ... [OK] file_sync_ status_ changed ... [OK] file_sync_ status_ disabled ... [OK] file_sync_ status_ disconnected ... [OK] file_sync_ status_ error ... [OK] file_sync_ status_ idle ... [OK] file_sync_ status_ starting ... [OK] file_sync_ status_ stopped ... [OK] file_sync_ status_ syncing ... [OK] file_sync_ status_ unknown ... [OK] status_ changed_ handler ... [OK] status_ changed_ handler_ after_status_ requested ... [OK] status_ changed_ handler_ after_status_ requested_ twice ... [OK] hErrorTestCase account_ info_returned ... [OK] change_ device_ settings ... [OK] change_ replication_ settings ... [OK] change_ volume_ settings ... [OK] connect_ files ... [OK] devices_ info_returned ... [OK] disable_ files ... [OK] disconnect_ files ... [OK] enable_ files ... [OK] remove_ device ... [OK] replications_ info ... [OK] restart_ files ... [OK]
ubuntuone.
BaseTestCase
runTest ... [OK]
DBusServiceMa
test_
test_
DBusServiceTe
test_
test_
test_
test_
test_
test_
test_
test_
FileSyncTestCase
test_
test_
test_
test_
test_
test_
test_
test_
test_
test_
test_
test_
OperationsAut
test_
test_
test_
test_
test_
test_
test_
test_
test_
test_
test_
test_
t...