Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/sharedprofile.py
blob: 61441a5a13ef7117da24d33dd604a980d7dc5d21 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
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)