Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/sugar-network
diff options
context:
space:
mode:
Diffstat (limited to 'sugar-network')
-rwxr-xr-xsugar-network146
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',