~tcole/ubuntuone-client/request-queue-predicates

« back to all changes in this revision

Viewing changes to ubuntuone/u1sync/main.py

  • Committer: tim.cole at canonical
  • Date: 2009-08-22 00:50:15 UTC
  • mfrom: (160.2.10 trunk)
  • Revision ID: tim.cole@canonical.com-20090822005015-6tdpcitod026r6z2
mergeĀ fromĀ trunk

Show diffs side-by-side

added added

removed removed

Lines of Context:
22
22
 
23
23
from __future__ import with_statement
24
24
 
 
25
import signal
25
26
import os
 
27
import sys
26
28
from errno import EEXIST
27
29
 
28
30
from optparse import OptionParser, SUPPRESS_HELP
31
33
gobject.set_application_name('u1sync')
32
34
 
33
35
from twisted.internet import reactor
34
 
from threading import Thread
 
36
from Queue import Queue
35
37
 
36
38
from ubuntuone.storageprotocol.oauth import OAuthToken
37
39
import ubuntuone.storageprotocol.dircontent_pb2 as dircontent_pb2
40
42
    show_tree, generic_merge)
41
43
from ubuntuone.u1sync.client import (
42
44
    ConnectionError, AuthenticationError, NoSuchShareError,
43
 
    Client)
 
45
    ForcedShutdown, Client)
44
46
from ubuntuone.u1sync.scan import scan_directory
45
47
from ubuntuone.u1sync.merge import (
46
48
    SyncMerge, ClobberServerMerge, ClobberLocalMerge, merge_trees)
76
78
 
77
79
class TreesDiffer(Exception):
78
80
    """Raised when diff tree differs."""
 
81
    def __init__(self, quiet):
 
82
        self.quiet = quiet
79
83
 
80
84
 
81
85
MERGE_ACTIONS = {
273
277
                            pre_merge=pre_merge, post_merge=post_merge,
274
278
                            partial_parent=("", False), name=u"")
275
279
    if differs:
276
 
        raise TreesDiffer()
 
280
        raise TreesDiffer(quiet=quiet)
277
281
 
278
282
def do_main(argv):
279
283
    """The main user-facing portion of the script."""
376
380
 
377
381
 
378
382
    if options.oauth is None:
379
 
        token = None
 
383
        passed_token = None
380
384
    else:
381
385
        try:
382
386
            (key, secret) = options.oauth.split(':', 2)
383
387
        except ValueError:
384
388
            parser.error("--oauth requires a key and secret together in the "
385
389
                         " form KEY:SECRET")
386
 
        token = OAuthToken(key, secret)
 
390
        passed_token = OAuthToken(key, secret)
387
391
 
388
392
    if options.share is not None:
389
393
        try:
394
398
    else:
395
399
        share_spec = None
396
400
 
397
 
    reactor_thread = Thread(target=
398
 
                            lambda: reactor.run(installSignalHandlers=False))
399
 
    reactor_thread.setDaemon(True)
400
 
    reactor_thread.start()
401
 
 
402
401
    client = Client(realm=options.realm, reactor=reactor)
403
402
 
404
 
    if token is None:
405
 
        should_create_token = (options.mode == "authorize")
406
 
        token = client.obtain_oauth_token(create_token=should_create_token)
407
 
 
408
 
    client.connect_ssl(options.host, int(options.port), options.no_ssl_verify)
409
 
 
410
 
    try:
411
 
        client.set_capabilities()
412
 
        client.oauth_from_token(token)
413
 
 
414
 
        if options.mode == "sync":
415
 
            do_sync(client=client, directory=directory, action=options.action,
416
 
                    dry_run=options.dry_run, quiet=options.quiet)
417
 
        elif options.mode == "init":
418
 
            do_init(client=client, share_spec=share_spec, directory=directory,
419
 
                    quiet=options.quiet, subtree_path=options.subtree)
420
 
        elif options.mode == "list-shares":
421
 
            do_list_shares(client=client)
422
 
        elif options.mode == "diff":
423
 
            do_diff(client=client, share_spec=share_spec, directory=directory,
424
 
                    quiet=options.quiet, subtree_path=options.subtree,
425
 
                    ignore_symlinks=False)
426
 
        elif options.mode == "authorize":
427
 
            if not options.quiet:
428
 
                print "Authorized."
429
 
    finally:
 
403
    signal.signal(signal.SIGINT, lambda s, f: client.force_shutdown())
 
404
    signal.signal(signal.SIGTERM, lambda s, f: client.force_shutdown())
 
405
 
 
406
    def run_client():
 
407
        """Run the blocking client."""
 
408
        if passed_token is None:
 
409
            should_create_token = (options.mode == "authorize")
 
410
            token = client.obtain_oauth_token(create_token=should_create_token)
 
411
        else:
 
412
            token = passed_token
 
413
 
 
414
        client.connect_ssl(options.host, int(options.port), options.no_ssl_verify)
 
415
 
430
416
        try:
 
417
            client.set_capabilities()
 
418
            client.oauth_from_token(token)
 
419
 
 
420
            if options.mode == "sync":
 
421
                do_sync(client=client, directory=directory,
 
422
                        action=options.action,
 
423
                        dry_run=options.dry_run, quiet=options.quiet)
 
424
            elif options.mode == "init":
 
425
                do_init(client=client, share_spec=share_spec,
 
426
                        directory=directory,
 
427
                        quiet=options.quiet, subtree_path=options.subtree)
 
428
            elif options.mode == "list-shares":
 
429
                do_list_shares(client=client)
 
430
            elif options.mode == "diff":
 
431
                do_diff(client=client, share_spec=share_spec,
 
432
                        directory=directory,
 
433
                        quiet=options.quiet, subtree_path=options.subtree,
 
434
                        ignore_symlinks=False)
 
435
            elif options.mode == "authorize":
 
436
                if not options.quiet:
 
437
                    print "Authorized."
 
438
        finally:
431
439
            client.disconnect()
 
440
 
 
441
    def capture_exception(queue, func):
 
442
        """Capture the exception from calling func."""
 
443
        try:
 
444
            func()
 
445
        except Exception, e:
 
446
            queue.put(sys.exc_info())
 
447
        else:
 
448
            queue.put(None)
432
449
        finally:
433
450
            reactor.callWhenRunning(reactor.stop)
434
 
            reactor_thread.join(1.0)
 
451
 
 
452
    queue = Queue()
 
453
    reactor.callInThread(capture_exception, queue, run_client)
 
454
    reactor.run(installSignalHandlers=False)
 
455
    exc_info = queue.get(True, 0.1)
 
456
    if exc_info:
 
457
        raise exc_info[0], exc_info[1], exc_info[2]
435
458
 
436
459
def main(*argv):
437
460
    """Top-level main function."""
450
473
        print "No matching share found."
451
474
    except ReadOnlyShareError:
452
475
        print "The selected action isn't possible on a read-only share."
453
 
    except KeyboardInterrupt:
 
476
    except (ForcedShutdown, KeyboardInterrupt):
454
477
        print "Interrupted!"
455
 
    except TreesDiffer:
456
 
        print "Trees differ."
 
478
    except TreesDiffer, e:
 
479
        if not e.quiet:
 
480
            print "Trees differ."
457
481
    else:
458
482
        return 0
459
483
    return 1