diff options
Diffstat (limited to 'sugar-network')
-rwxr-xr-x | sugar-network | 146 |
1 files changed, 108 insertions, 38 deletions
diff --git a/sugar-network b/sugar-network index 2dd1194..bcc7015 100755 --- a/sugar-network +++ b/sugar-network @@ -15,67 +15,137 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. -from sugar_network.toolkit import application, sugar +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 enforce +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') -command = Option( - 'if context implementation supports several commands, ' \ - 'specify one of them to launch', - default='activity', short_option='-C') +_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( - 'CONTEXT [RESTRICTION] [ARGS]\n' - 'if context is associatad with software, launch one of its ' - 'implementations') - def launch(self): - enforce(self.args, 'Context is not specified') - #context = self.args.pop(0) - raise NotImplementedError() + 'send POST API request') + def POST(self): + self._call('POST', sys.stdin.read()) @application.command( - 'CONTEXT\n' - 'if context is associatad with software, download one of its ' - 'implementations and place it to ~/Activities') - def checkin(self): - enforce(self.args, 'Context is not specified') - #context = self.args.pop(0) - raise NotImplementedError() + 'send PUT API request') + def PUT(self): + self._call('PUT', sys.stdin.read()) @application.command( - 'CONTEXT\n' - 'delete all implementations downloaded by "checkin" command') - def checkout(self): - enforce(self.args, 'Context is not specified') - #context = self.args.pop(0) - raise NotImplementedError() + '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]) -Option.seek('sugar-network') -Option.seek('sugar-network', [application.debug]) +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.', - where={ - 'CONTEXT': - 'context GUID or name context should implement', - 'RESTRICTION': - 'particular context implementation in form of:\n' \ - '=|>=|< VERSION', - 'ARGS': - 'arbitrary command-line arguments to pass as-is to ' \ - 'launching context implementation', - }, config_files=[ '/etc/sweets.conf', '~/.config/sweets/config', |