#!/usr/bin/env python # Copyright (C) 2012 Aleksey Lim # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program 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 General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . import os import re import json import shlex import locale from os.path import join import active_document as ad from sugar_network import local, sugar, toolkit, IPCClient from sugar_network.resources.volume import Volume, Request from sugar_network.local.mountset import Mountset from sugar_network.local.mounts import HomeMount, RemoteMount from active_toolkit.options import Option from active_toolkit import printf, application, coroutine, enforce anonymous = Option( 'use anonymous user to access to Sugar Network server; ' 'only read-only operations are available in this mode', default=False, type_cast=Option.bool_cast, action='store_true', name='anonymous') _ESCAPE_VALUE_RE = re.compile('([^\[\]\{\}0-9][^\]\[\{\}]+)') class Application(application.Application): def __init__(self, **kwargs): application.Application.__init__(self, **kwargs) application.rundir.value = join(local.local_root.value, 'run') @application.command( 'send POST API request') def POST(self): self._call('POST', sys.stdin.read()) @application.command( 'send PUT API request') def PUT(self): self._call('PUT', sys.stdin.read()) @application.command( 'send GET API request') def GET(self): self._call('GET', None) def _call(self, method, content=None): request = Request(method=method) request.content = content response = ad.Response() reply = [] if self.args and self.args[0].startswith('/'): path = self.args.pop(0).strip('/').split('/') request['document'] = path.pop(0) if path: request['guid'] = path.pop(0) if path: request['prop'] = path.pop(0) for arg in self.args: arg = shlex.split(arg) if not arg: continue arg = arg[0] if '=' not in arg: reply.append(arg) continue arg, value = arg.split('=', 1) arg = arg.strip() enforce(arg, 'No argument name in %r expression', arg) if arg in request: if isinstance(request[arg], basestring): request[arg] = [request[arg]] request[arg].append(value) else: request[arg] = value pid_path = None cp = None try: if not self.check_for_instance(): pid_path = self.new_instance() if anonymous.value: sugar.uid = lambda: 'anonymous' sugar.nickname = lambda: 'anonymous' sugar.color = lambda: '#000000,#000000' else: toolkit.ensure_dsa_pubkey(sugar.profile_path('owner.key')) volume = Volume(local.db_path()) cp = Mountset(volume) cp['~'] = HomeMount(volume) cp['/'] = RemoteMount(volume) cp['/'].mounted.wait() else: cp = IPCClient() def events_cb(events): for event in events: pass coroutine.spawn(events_cb, cp.subscribe()) coroutine.dispatch() result = cp.call(request, response) finally: cp.close() if pid_path: os.unlink(pid_path) if result is not None: if reply: for key in reply: key = _ESCAPE_VALUE_RE.sub("'\\1'", key) print eval('result%s' % key) else: print json.dumps(result, indent=2) # New defaults application.debug.value = sugar.logger_level() Option.seek('main', [application.debug, anonymous]) Option.seek('local', [local.api_url, local.layers]) locale.setlocale(locale.LC_ALL, '') app = Application( name='sugar-network', description='Sugar Network client utility', epilog='See http://wiki.sugarlabs.org/go/Sugar_Network ' \ 'for details.', config_files=[ '/etc/sweets.conf', '~/.config/sweets/config', sugar.profile_path('sweets.conf'), ], stop_args=['launch']) app.start()