From eca8880ff44e29920c58be3a80ca45527ef8e960 Mon Sep 17 00:00:00 2001 From: Simon Schampijer Date: Wed, 19 Dec 2007 23:12:51 +0000 Subject: Initial import of the shared profile --- 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) -- cgit v0.9.1