Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sharedprofile.py114
-rwxr-xr-xwebactivity.py8
2 files changed, 121 insertions, 1 deletions
diff --git a/sharedprofile.py b/sharedprofile.py
new file mode 100644
index 0000000..61441a5
--- /dev/null
+++ b/sharedprofile.py
@@ -0,0 +1,114 @@
+'''Adapter module to synchronize sanitized versions of the profile
+directory with other activity instances.
+'''
+
+import shutil
+import tempfile
+import os
+import stat
+import subprocess
+import re
+
+from sugar import env
+
+def _copy_dir(src, dst):
+ ''' recursively copying folder src, the target folder dst exist already '''
+ names = os.listdir(src)
+ for name in names:
+ srcname = os.path.join(src, name)
+ dstname = os.path.join(dst, name)
+ try:
+ if os.path.isdir(srcname):
+ if not os.path.exists(dstname):
+ os.mkdir(dstname)
+ _copy_dir(srcname, dstname)
+ else:
+ shutil.copy2(srcname, dstname)
+ except (IOError, os.error), why:
+ print 'Can\'t copy %s to %s: %s' % (`srcname`, `dstname`, str(why))
+
+def _chmod_dir(folder):
+ ''' chmod a folder recursively '''
+ names = os.listdir(folder)
+ for name in names:
+ name = os.path.join(folder, name)
+ try:
+ mode = os.stat(name)[stat.ST_MODE]
+ os.chmod(name, (mode | stat.S_IWGRP | stat.S_IRGRP))
+ if os.path.isdir(name):
+ _chmod_dir(name)
+ except (IOError, os.error), why:
+ print 'Can\'t chmod %s: %s' % (`name`, str(why))
+
+def create_local_profile(sar):
+ ''' create local profile from shared profile'''
+
+ profile_inst = os.path.join(sar, 'instance/profile')
+ profile_data = os.path.join(sar, 'data/profile')
+
+ # copy old profile data if exist
+ if not os.path.exists(profile_inst):
+ os.mkdir(profile_inst)
+ if os.path.exists(profile_data):
+ folder = os.readlink(profile_data)
+ if os.path.exists(folder):
+ _copy_dir(folder, profile_inst)
+
+def update_shared_profile(sar):
+ '''impose appropriate permissions and synchronize
+ with the shared profile '''
+
+ profile_inst = os.path.join(sar, 'instance/profile')
+ profile_data = os.path.join(sar, 'data/profile')
+ profile_data_tmp = os.path.join(sar, 'data/profile_tmp')
+
+ # copy profile to $STAGING_AREA
+ staging_area = tempfile.mkdtemp(dir=os.path.join(sar, 'instance'))
+ _copy_dir(profile_inst, staging_area)
+
+ # change entries to be rw for the group
+ _chmod_dir(staging_area)
+
+ # create a tempfile in $SAR/data
+ new_profile = tempfile.mkdtemp(dir=os.path.join(sar, 'data'))
+ os.chmod(new_profile, 0770)
+
+ # clone the contents of the $STAGING_AREA into $NEW_PROFILE
+ _copy_dir(staging_area, new_profile)
+ shutil.rmtree(staging_area)
+
+ # atomically swing symlink $SAR/data/profile to point to $NEW_PROFILE
+ os.symlink(new_profile, profile_data_tmp)
+ os.rename(profile_data_tmp, profile_data)
+
+def _in_use(folder):
+ ''' check if there are processes running under the uid
+ owning the folder
+ '''
+ if env.is_emulator():
+ # FIXME: must find a way to deal with this in sugar-jhbuild
+ return True
+ uid = os.stat(folder)[stat.ST_UID]
+ fdp = subprocess.Popen(['ps', '--no-headers', '-f', 'U', str(uid)],
+ stdout=subprocess.PIPE)
+ data = fdp.stdout.read()
+ command = '.*(%d).*' % uid
+ ret = re.compile(command).match(data)
+ if ret:
+ return True
+ return False
+
+def garbage_collector(sar):
+ ''' garbage-collection step in order to reclaim the resources used by
+ old revisions of the profile
+ '''
+ sar_data = os.path.join(sar, 'data')
+ names = os.listdir(sar_data)
+ for name in names:
+ path = os.path.join(sar_data, name)
+ if os.path.isdir(path) and not os.path.islink(path):
+ path_profile = os.readlink(os.path.join(sar, 'data/profile'))
+ if not path_profile == path and not _in_use(path):
+ shutil.rmtree(path)
+
+
diff --git a/webactivity.py b/webactivity.py
index 8ff8db4..98658e5 100755
--- a/webactivity.py
+++ b/webactivity.py
@@ -35,10 +35,14 @@ from sugar.graphics.alert import Alert
from sugar.graphics.icon import Icon
from sugar import mime
+import sharedprofile
+
+sharedprofile.create_local_profile(activity.get_activity_root())
+
PROFILE_VERSION = 1
_profile_version = 0
-_profile_path = os.path.join(activity.get_activity_root(), 'data/gecko')
+_profile_path = os.path.join(activity.get_activity_root(), 'instance/profile')
_version_file = os.path.join(_profile_path, 'version')
if os.path.exists(_version_file):
@@ -322,6 +326,8 @@ class WebActivity(activity.Activity):
f.write(self.model.serialize())
finally:
f.close()
+ sharedprofile.update_shared_profile(activity.get_activity_root())
+ sharedprofile.garbage_collector(activity.get_activity_root())
def _link_add_button_cb(self, button):
_logger.debug('button: Add link: %s.' % self.current)