Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAleksey Lim <alsroot@sugarlabs.org>2012-08-15 21:33:03 (GMT)
committer Aleksey Lim <alsroot@sugarlabs.org>2012-08-15 21:33:03 (GMT)
commite9efce579d2e07360fd98393ced2206fdcf5d688 (patch)
tree07b9d1a385a80cc7267c7549242745e49c68cf27
parentb2d40c3e077c78331bd581d199839faba97e7bd5 (diff)
Mount.mounted is an Event to simplify waiting for connection; handy volume_commands to install scripts
-rwxr-xr-xsugar-network-service64
-rw-r--r--sugar_network/local/activities.py2
-rw-r--r--sugar_network/local/mounts.py18
-rw-r--r--sugar_network/local/mountset.py36
-rw-r--r--tests/__init__.py12
-rwxr-xr-xtests/units/mountset.py8
6 files changed, 87 insertions, 53 deletions
diff --git a/sugar-network-service b/sugar-network-service
index 5df3b53..ce425b3 100755
--- a/sugar-network-service
+++ b/sugar-network-service
@@ -16,6 +16,9 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import os
+import sys
+import json
+import shlex
import signal
import locale
import logging
@@ -88,21 +91,12 @@ class Application(application.Application):
coroutine.signal(signal.SIGCHLD, self.__SIGCHLD_cb)
@application.command(
- '[PREFIX-PATH [CONTEXT-GUID ..]]\n'
- 'Index local Sugar Network database; if CONTEXT-GUIDs '
- 'were specified, make these context favorited')
+ 'index local Sugar Network database')
def index(self):
if self.check_for_instance():
printf.info('%s already started, no need in index', self.name)
return
- root = ''
- if self.args:
- root = abspath(self.args.pop(0))
- local.activity_dirs.value = [root + abspath(i) \
- for i in local.activity_dirs.value]
- local.local_root.value = root + local.local_root.value
-
if not exists(sugar.profile_path('owner.key')):
# Command was launched in foreign environment
sugar.uid = lambda: 'index'
@@ -113,25 +107,16 @@ class Application(application.Application):
volume = Volume(self._db_path)
try:
volume.populate()
- activities.populate(volume['context'], local.activity_dirs.value,
- root)
-
- directory = volume['context']
- while self.args:
- context = self.args.pop(0)
- if directory.exists(context):
- directory.update(context, keep=True)
- else:
- printf.info('Cannot find %r context', context)
+ activities.populate(volume['context'], local.activity_dirs.value)
finally:
volume.close()
@application.command(
- '[PATH]\n'
- 'start sneakernet synchronization; if PATH is specified, '
- 'use it as a synchronization directory; otherwise, '
- 'look for mounts (in --mounts-root) that contain '
- 'sugar-network-sync/ subdirectory')
+ 'start sneakernet synchronization; if PATH is specified, '
+ 'use it as a synchronization directory; otherwise, '
+ 'look for mounts (in --mounts-root) that contain '
+ 'sugar-network-sync/ subdirectory',
+ args='[PATH]')
def offline_sync(self):
with self._rendezvous():
path = None
@@ -140,6 +125,19 @@ class Application(application.Application):
Client.call('POST', cmd='start_sync', rewind=True, path=path)
self._events['sync_complete'].wait()
+ @application.command(hidden=True)
+ def POST(self):
+ self._call('POST', sys.stdin.read())
+
+ @application.command(hidden=True)
+ def PUT(self):
+ self._call('PUT', sys.stdin.read())
+
+ @application.command(hidden=True)
+ def GET(self):
+ result = self._call('GET', None)
+ print json.dumps(result, indent=2)
+
@application.command(
'start service and log to standard output')
def debug(self):
@@ -245,6 +243,22 @@ class Application(application.Application):
if server is not None:
server.kill()
+ def _call(self, method, content=None):
+ kwargs = {}
+ for arg in self.args:
+ pair = shlex.split(arg)
+ if not pair:
+ continue
+ pair = pair[0]
+ enforce('=' in pair, 'No "=" assign symbol in %r expression', arg)
+ arg, value = pair.split('=', 1)
+ arg = arg.strip()
+ enforce(arg, 'No argument name in %r expression', arg)
+ kwargs[arg] = value
+
+ with self._rendezvous():
+ return Client.call(method, content=content, **kwargs)
+
@property
def _db_path(self):
return join(local.local_root.value, 'local')
diff --git a/sugar_network/local/activities.py b/sugar_network/local/activities.py
index 7d67e66..20dcf9c 100644
--- a/sugar_network/local/activities.py
+++ b/sugar_network/local/activities.py
@@ -78,7 +78,7 @@ def monitor(contexts, paths):
inotify.serve_forever()
-def populate(contexts, paths, prefix):
+def populate(contexts, paths):
inotify = _Inotify(contexts)
inotify.add_watch = lambda *args: None
inotify.setup(paths)
diff --git a/sugar_network/local/mounts.py b/sugar_network/local/mounts.py
index 8318627..747d3fa 100644
--- a/sugar_network/local/mounts.py
+++ b/sugar_network/local/mounts.py
@@ -44,7 +44,7 @@ class _Mount(object):
def __init__(self):
self.mountpoint = None
self.publisher = None
- self._mounted = False
+ self.mounted = coroutine.Event()
@property
def name(self):
@@ -54,14 +54,13 @@ class _Mount(object):
def private(self):
return type(self) in (LocalMount, HomeMount)
- @property
- def mounted(self):
- return self._mounted
-
def set_mounted(self, value):
- if self._mounted == value:
+ if self.mounted.is_set() == value:
return
- self._mounted = value
+ if value:
+ self.mounted.set()
+ else:
+ self.mounted.clear()
self.publish({
'event': 'mount' if value else 'unmount',
'mountpoint': self.mountpoint,
@@ -331,7 +330,7 @@ class RemoteMount(ad.CommandsProcessor, _Mount, _ProxyCommands):
return self._proxy_call(request, response, super_call)
def set_mounted(self, value):
- if value != self.mounted:
+ if value != self.mounted.is_set():
if value:
self.mount()
else:
@@ -361,7 +360,8 @@ class RemoteMount(ad.CommandsProcessor, _Mount, _ProxyCommands):
def mount(self, url=None):
if url and url not in self._api_urls:
self._api_urls.append(url)
- if self._api_urls and not self.mounted and not self._connections:
+ if self._api_urls and not self.mounted.is_set() and \
+ not self._connections:
self._connections.spawn(self._connect)
def _connect(self):
diff --git a/sugar_network/local/mountset.py b/sugar_network/local/mountset.py
index e9e081e..f81476b 100644
--- a/sugar_network/local/mountset.py
+++ b/sugar_network/local/mountset.py
@@ -69,7 +69,7 @@ class Mountset(dict, ad.CommandsProcessor, SyncCommands):
def mounts(self):
result = []
for path, mount in self.items():
- if path == '/' or mount.mounted:
+ if path == '/' or mount.mounted.is_set():
result.append({
'mountpoint': path,
'name': mount.name,
@@ -84,7 +84,35 @@ class Mountset(dict, ad.CommandsProcessor, SyncCommands):
return False
if mountpoint == '/':
mount.set_mounted(True)
- return mount.mounted
+ return mount.mounted.is_set()
+
+ @ad.volume_command(method='PUT', cmd='checkin')
+ def checkin(self, mountpoint, request):
+ mount = self.get(mountpoint)
+ enforce(mount is not None, 'No such mountpoint')
+ mount.mounted.wait()
+
+ for guid in (request.content or '').split():
+ _logger.info('Checkin %r context', guid)
+ mount.call(
+ ad.Request(method='PUT', document='context', guid=guid,
+ accept_language=[self._locale],
+ content={'keep_impl': 2, 'keep': False}),
+ ad.Response())
+
+ @ad.volume_command(method='PUT', cmd='keep')
+ def keep(self, mountpoint, request):
+ mount = self.get(mountpoint)
+ enforce(mount is not None, 'No such mountpoint')
+ mount.mounted.wait()
+
+ for guid in (request.content or '').split():
+ _logger.info('Keep %r context', guid)
+ mount.call(
+ ad.Request(method='PUT', document='context', guid=guid,
+ accept_language=[self._locale],
+ content={'keep': True}),
+ ad.Response())
@ad.volume_command(method='POST', cmd='publish')
def republish(self, request):
@@ -100,11 +128,13 @@ class Mountset(dict, ad.CommandsProcessor, SyncCommands):
try:
result = ad.CommandsProcessor.call(self, request, response)
except ad.CommandNotFound:
+ enforce('mountpoint' in request, 'No \'mountpoint\' argument')
request.pop('mountpoint')
mount = self[mountpoint]
if mountpoint == '/':
mount.set_mounted(True)
- enforce(mount.mounted, '%r is not mounted', mountpoint)
+ enforce(mount.mounted.is_set(),
+ '%r is not mounted', mountpoint)
result = mount.call(request, response)
except Exception:
util.exception(_logger, 'Failed to call %s on %r',
diff --git a/tests/__init__.py b/tests/__init__.py
index 6235904..a1a83af 100644
--- a/tests/__init__.py
+++ b/tests/__init__.py
@@ -242,17 +242,7 @@ class Test(unittest.TestCase):
def start_ipc_and_restful_server(self, classes=None, **kwargs):
pid = self.fork(self.restful_server, classes)
self.start_server(classes)
-
- if not self.mounts['/'].mounted:
-
- def wait_connect(event):
- if event.get('mountpoint') == '/' and event['event'] == 'mount':
- connected.set()
-
- connected = coroutine.Event()
- self.mounts.connect(wait_connect)
- connected.wait()
-
+ self.mounts['/'].mounted.wait()
return pid
def restful_server(self, classes=None):
diff --git a/tests/units/mountset.py b/tests/units/mountset.py
index 7fddceb..9188509 100755
--- a/tests/units/mountset.py
+++ b/tests/units/mountset.py
@@ -188,7 +188,7 @@ class MountsetTest(tests.Test):
mountset['/'] = RemoteMount(mountset.home_volume)
self.assertEqual(['/'], [i['mountpoint'] for i in mountset.mounts()])
- assert not mountset['/'].mounted
+ assert not mountset['/'].mounted.is_set()
self.assertEqual(0, client.Context.cursor().total)
self.assertRaises(RuntimeError, client.Context(type='activity', title='', summary='', description='').post)
@@ -199,7 +199,7 @@ class MountsetTest(tests.Test):
self.assertRaises(RuntimeError, client.Context(type='activity', title='', summary='', description='').post)
self.mounted.wait()
self.mounted.clear()
- assert mountset['/'].mounted
+ assert mountset['/'].mounted.is_set()
self.assertEqual([('mount', '/')], self.mount_events)
del self.mount_events[:]
@@ -217,7 +217,7 @@ class MountsetTest(tests.Test):
self.mounted.wait()
self.mounted.clear()
- assert not mountset['/'].mounted
+ assert not mountset['/'].mounted.is_set()
self.assertEqual([('unmount', '/')], self.mount_events)
del self.mount_events[:]
self.assertEqual(0, client.Context.cursor().total)
@@ -230,7 +230,7 @@ class MountsetTest(tests.Test):
self.assertRaises(RuntimeError, client.Context(type='activity', title='', summary='', description='').post)
self.mounted.wait()
self.mounted.clear()
- assert mountset['/'].mounted
+ assert mountset['/'].mounted.is_set()
self.assertEqual([('mount', '/')], self.mount_events)
del self.mount_events[:]