source: products/qPloneSkinDump/tags/0.7.4/skin_template/Extensions/utils.py @ 1552

Last change on this file since 1552 was 1, checked in by myroslav, 19 years ago

Building directory structure

  • Property svn:eol-style set to native
File size: 21.2 KB
Line 
1import os, sys, re, string
2from StringIO import StringIO
3from time import gmtime, strftime
4from zLOG import LOG, INFO
5from zExceptions import BadRequest
6from App.config import getConfiguration
7from Products.CMFCore.utils import getToolByName
8from Products.CMFCore.DirectoryView import addDirectoryViews
9from Products.%(SKIN_PRODUCT_NAME)s.config import *
10
11######################################################################
12##                      IMPORTING UTILS                             ##
13######################################################################
14osp = os.path
15ALLOWED_IMPORT_POLICY = ["only_new", "backup", "overwrite"]
16INTRO_TO_INSTANCE = "< Started copying object files from Product import directory to Instance one."
17SUMMARY_TO_INSTANCE = "> Finished copying."
18INTRO_TO_ROOT = "< Started import %%s file[s] with '%%s' policy."
19SUMMARY_TO_ROOT = "> Finished importing."
20INTRO_CLEAN = "< Started cleaning Instance import directory."
21SUMMARY_CLEAN = "> Finished cleaning."
22CREXP_INVALID_ID = re.compile('^The id \"(.*?)\" is invalid - it is already in use.$', re.DOTALL|re.IGNORECASE|re.MULTILINE)
23CSS_BASE_IDS_QPSD053 = ['id','expression','enabled','cookable','media','rel','title','rendering']   # supporting qPSD-0.5.3 version
24################    CHECK IMPORTING    ################
25def checkIfImport():
26    """ Return if perform importing, based on checking
27        *zexp files in <SkinProduct>/import directory.
28    """
29    instance_ipath, product_ipath = getImportedPathes()
30    product_ilist = [i for i in os.listdir(product_ipath) \
31                     if osp.isfile(osp.join(product_ipath,i)) and i.endswith('.zexp')]
32    if product_ilist:
33        return 1
34    return 0
35
36################    IMPORTING TO PLONE'S IMPORT DIR   ################
37def getImportedPathes():
38    """ Return Plone instance and Skin product import pathes."""
39    # Based on instance path, construct import pathes
40    cfg = getConfiguration()
41    instance_ipath = osp.join(cfg.instancehome, "import")
42    product_ipath = osp.join(cfg.instancehome, 'Products', PRODUCT_NAME, "import")
43    # Check presence of Product import directory
44    if not osp.isdir(product_ipath):       
45        raise BadRequest, "Skin Product's import directory '%%s' - does not exist or is'nt direcory" %% product_ipath
46    # Check presence of Instance import directory
47    if not osp.isdir(instance_ipath):
48        raise BadRequest, "Instance import directory '%%s' - does not exist or isn't direcory" %% instance_ipath
49    return [instance_ipath, product_ipath]
50
51def copyFile(src_dir, dst_dir, f_name):
52    """ Copy file from src_dir to dst_dir under original name."""
53    try:
54        src_file = open(osp.join(src_dir, f_name),"rb")
55        dst_file = open(osp.join(dst_dir, f_name),"wb")
56        dst_file.write(src_file.read())
57        dst_file.close()
58        src_file.close()
59    except Exception, e:
60        msg = "!!! In copying files from <%%s> dir to <%%s> dir exception occur. Details: %%s." %% (src_dir,dst_dir, str(e))
61        print >> import_out, msg
62        LOG('performImportToPortal',INFO,'copyFile', msg)
63
64def moveToTemp(same_instance_files, instance_ipath, temp_dir_path):
65    """ Move samenamed files from Instanse's dir to temp dir."""
66    os.mkdir(temp_dir_path) # Create temp back_[date] dir
67    try:
68        [copyFile(instance_ipath, temp_dir_path, f_name) for f_name in same_instance_files]
69        [os.remove(osp.join(instance_ipath, f_name)) for f_name in same_instance_files]
70    except Exception, e:
71        msg = "!!! Exception occur during moving files from Instance's dir to temp dir. Detaile:%%s." %% str(e)
72        print >> import_out, msg
73        LOG('performImportToPortal',INFO,'moveToTemp', msg)
74   
75def copyToInstanceImport():
76    """ Perform copying imported files from <SkinProduct>/import dir
77        to Plone's instance import dir.
78    """
79    print >> import_out, INTRO_TO_INSTANCE
80    instance_ipath, product_ipath = getImportedPathes()
81    # Compose temp dir back_[date] dir path in Instance import directory
82    temp_dir_id = "back_%%s" %% strftime("%%Y%%m%%d%%H%%M%%S", gmtime())
83    temp_dir_path = osp.join(instance_ipath, temp_dir_id)
84    # Get *.zexp files from Skin Product's import dir and Plone's instance import dir files
85    product_ilist = [i for i in os.listdir(product_ipath) \
86                     if osp.isfile(osp.join(product_ipath,i)) and i.endswith('.zexp')]
87    instance_ilist = [i for i in os.listdir(instance_ipath) \
88                      if osp.isfile(osp.join(instance_ipath,i)) and i.endswith('.zexp')]
89    # Check for presence samenamed files in Instance and Product import directories.
90    same_instance_files = [f_name for f_name in instance_ilist if f_name in product_ilist]
91    if same_instance_files:
92        moveToTemp(same_instance_files, instance_ipath, temp_dir_path)
93    # Copy all *zexp files from Product's import dir to Instance's import dir
94    [copyFile(product_ipath, instance_ipath, f_name) for f_name in product_ilist]
95    print >> import_out, SUMMARY_TO_INSTANCE
96    return [instance_ipath, product_ipath, temp_dir_path, product_ilist]
97
98################    IMPORTING TO PORTAL   ################
99def importObject(portal, file_name):
100    """ Work around old Zope bug in importing."""
101    try:
102        portal.manage_importObject(file_name)
103    except:
104        portal._p_jar = portal.Destination()._p_jar
105        portal.manage_importObject(file_name)
106
107def makeBackUp(portal, portal_objects, temp_dir_path, obj_id):
108    """ Perfom backup same named portal objects in temp folder."""
109    # Get id of temp folder-object
110    durty_path,temp_id = osp.split(temp_dir_path)
111    if not temp_id:
112        durty_path,temp_id = osp.split(durty_path)
113    # Get temp folder-object
114    if temp_id not in portal_objects:
115        portal.invokeFactory('Folder', id=temp_id)
116        print >> import_out, "! Created '%%s' backup directory with same-ids " \
117                             "objects from portal root." %% temp_id
118    temp_dir = getattr(portal, temp_id)
119    # Move object with same id to temp folder-object
120    get_transaction().commit(1)
121    obj = portal.manage_cutObjects(ids=[obj_id])
122    temp_dir.manage_pasteObjects(obj)
123    print >> import_out, "! '%%s' Object moved from portal root to '%%s' backup directory." %% (obj_id, temp_id)
124
125def performImport(portal, temp_dir_path, file_name):
126    """ Importing an object to portal."""
127    portal_objects = portal.objectIds()
128    try:
129        portal.manage_importObject(file_name)
130    except Exception, e:
131        msg = str(e)
132        is_invalid_id = CREXP_INVALID_ID.match(msg)
133        if is_invalid_id:
134            obj_id = is_invalid_id.group(1)
135            if IMPORT_POLICY == "only_new":
136                msg = "! Object with '%%s' id was not importing because it's already exist " \
137                      "in portal root." %% obj_id
138                print >> import_out, msg
139            elif IMPORT_POLICY == "backup":
140                makeBackUp(portal, portal_objects, temp_dir_path, obj_id)
141                importObject(portal, file_name)
142            elif IMPORT_POLICY == "overwrite":
143                portal.manage_delObjects(ids=[obj_id])
144                importObject(portal, file_name)
145        else:
146            # work around old Zope bug in importing
147            portal._p_jar = portal.Destination()._p_jar
148            portal.manage_importObject(file_name)
149
150def importToPortalRoot(portal, product_file_names, temp_dir_path):
151    """ Import all objects from *zexp files to portal root (based on IMPORT_POLICY)."""
152    if not IMPORT_POLICY in ALLOWED_IMPORT_POLICY:
153        raise Exception("%%s - wrong import policy in '%%s/config.py' file. Must be one of the %%s" \
154                        %% (IMPORT_POLICY, PRODUCT_NAME, ALLOWED_IMPORT_POLICY) )
155    print >> import_out, INTRO_TO_ROOT %% (product_file_names, IMPORT_POLICY)
156    for file_name in product_file_names:
157        try:
158            performImport(portal, temp_dir_path, file_name)
159        except Exception, error:
160            msg = '!!! Under "%%s" policy importing exception occur: %%s.' %% (IMPORT_POLICY, str(error))
161            print >> import_out, msg
162            LOG('performImportToPortal',INFO,'importToPortalRoot', msg)
163    print >> import_out, SUMMARY_TO_ROOT
164
165################    CLEANING PLONE'S IMPORT DIR   ################
166def cleanInstanceImport(instance_ipath, product_file_names, temp_dir_path):
167    """ Cleaning Plone's import dir."""
168    print >> import_out, INTRO_CLEAN
169    # Erase all copied *zexp files from Instance's import dir
170    for f_name in product_file_names:
171        f_path = osp.join(instance_ipath, f_name)
172        if osp.exists(f_path) and osp.isfile(f_path):
173            os.remove(f_path)
174        else:
175            msg = '! "%%s" file was not deleted from "%%s" import directory.' %%\
176                   (f_name, osp.join(instance_ipath))
177            print >> import_out, msg
178            LOG('performImportToPortal',INFO,'cleanInstanceImport', msg)
179    # Move all files from temp back_[date] dir to Instance's import dir
180    if osp.exists(temp_dir_path) and osp.isdir(temp_dir_path):
181        f_names = os.listdir(temp_dir_path)
182        try:
183            [copyFile(temp_dir_path, instance_ipath, f_name) for f_name in f_names]
184            [os.remove(osp.join(temp_dir_path, f_name)) for f_name in f_names]
185            # Erase temp back_[date] dir
186            os.rmdir(temp_dir_path)
187        except Exception, e:
188            msg = "!!! In moving files from temp dir to Instance's import dir exception occur."
189            print >> import_out, msg
190            LOG('performImportToPortal',INFO,'moveFromTempToImport', msg)
191    print >> import_out, SUMMARY_CLEAN
192
193################    MAIN    ################
194def performImportToPortal(portal):
195    """ Import objects from Skin Product to Portal root."""
196    globals()['import_out'] = StringIO()
197    instance_ipath, product_ipath, temp_dir_path, product_file_names = copyToInstanceImport()
198    if product_file_names:
199        importToPortalRoot(portal, product_file_names, temp_dir_path)
200        cleanInstanceImport(instance_ipath, product_file_names, temp_dir_path)
201    else:
202        print >> import_out, "!!! Failure importing: there is no file for importing to be found."
203    result = import_out
204    del globals()['import_out']
205    return result.getvalue()
206
207######################################################################
208##              INSTALLATION/UNINSTALLATION UTILS                   ##
209######################################################################
210CSS_REG_PROPS = ['id', 'expression', 'enabled', 'cookable', 'cacheable' \
211                ,'media', 'rel', 'title', 'rendering', 'compression']
212JS_REG_PROPS = ['id', 'expression', 'enabled', 'cookable', 'cacheable' \
213               ,'inline', 'compression']
214
215def installSkin(portal, pp_up, out):
216    # Checking for presense SKIN_NAME in portal_skins directory view or among Skin Names
217    skinsTool = getToolByName(portal, 'portal_skins')
218    # Get unique product_skin_name and remember it in case of differ from SKIN_NAME.
219    product_skin_name = SKIN_NAME
220    skin_names = skinsTool.getSkinSelections()
221    if product_skin_name in skin_names:
222        idx = 0
223        while product_skin_name in skin_names:
224            product_skin_name = SKIN_NAME + str(idx)
225            idx += 1
226        addProperty(pp_up, 'q_actual_skin_name', product_skin_name, 'string', out)
227    # Add directory views
228    layer_skin_name = string.lower(SKIN_NAME)
229    addDirectoryViews(skinsTool, 'skins', GLOBALS)
230    print >> out,  "- added '%%s' directory views to portal_skins." %% layer_skin_name
231    # Get Default skin and remember it for backup on uninstallig
232    default_skin = skinsTool.getDefaultSkin()
233    addProperty(pp_up, 'q_default_skin', default_skin, 'string', out)
234    # Building list of layers for NEW SKIN
235    base_path = skinsTool.getSkinPath(BASE_SKIN_NAME)
236    new_path = map( string.strip, string.split(base_path,',') )
237    if layer_skin_name in new_path :
238        print >> out, "- %%s layer already present in '%%s' skin." %% (layer_skin_name, BASE_SKIN_NAME)
239        # Remove layer_skin_name from current position.
240        del new_path[new_path.index(layer_skin_name)]
241    # Add layer_skin_name just after 'custom' position
242    try: 
243        new_path.insert(new_path.index('custom')+1, layer_skin_name)
244    except ValueError:
245        new_path.append(layer_skin_name)
246    new_path = string.join(new_path, ', ')
247    # Add NEW Skin and set it as dafault
248    skinsTool.addSkinSelection(product_skin_name, new_path, make_default=1)
249    print >> out, "Added %%s skin, bassed on %%s and set as default." %% (product_skin_name, BASE_SKIN_NAME)
250
251def uninstallSkin(skinsTool, actual_skin_name, initial_skin):
252    # Get 'portal_skins' object and list available skin names
253    # And remove SKIN_NAME from available skins, if it present
254    skin_names = skinsTool.getSkinSelections()
255    if actual_skin_name in skin_names :
256        skinsTool.manage_skinLayers(chosen=(actual_skin_name,), del_skin=1, REQUEST=None)
257        skin_names.remove(actual_skin_name)
258    # Remove product skin directory from skins tool
259    # AND Remove skin-product layer from available skins
260    skin_layer = SKIN_NAME.lower()
261    if skin_layer in skinsTool.objectIds():
262        skinsTool.manage_delObjects(skin_layer)
263    for skin_name in skin_names:
264        path = skinsTool.getSkinPath(skin_name)
265        path = [i.strip() for i in  path.split(',')]
266        if skin_layer in path:
267            path.remove(skin_layer)
268            path = ','.join(path)
269            skinsTool.addSkinSelection(skin_name, path)
270    # If current default skin == actual_skin_name
271    # Set default skin in initial one (if initial skin still exist)
272    # or in 1st from available skin names list.
273    current_default_skin = skinsTool.getDefaultSkin()
274    if current_default_skin == actual_skin_name:
275        if initial_skin in skin_names :
276            skinsTool.manage_properties(default_skin=initial_skin, REQUEST=None)
277        elif len(skin_names)>0 :
278            skinsTool.manage_properties(default_skin=skin_names[0], REQUEST=None)
279
280def addProperty(p_sheet, p_id, p_value, p_type, out):
281    if p_sheet.hasProperty(p_id):
282        p_sheet._delProperty(p_id)
283    p_sheet._setProperty(p_id, p_value, p_type)
284    print >> out, "... added %%s PropertySheet to %%s." %% (p_id, p_sheet.getId())
285
286def getResourceProperties(obj, prop_list, dflt=''):
287    """ Return list of 2 items list-[property name, property value]."""
288    properties=[]
289    for prop in prop_list:
290        accessor = getattr(obj, 'get%%s' %% prop.capitalize(), None)
291        if accessor:
292            properties.append([prop, accessor() or dflt])
293    return properties
294
295def registerResource(pp_up, portal_res, resRegisterFunction, out \
296                    ,RESOURCE_SKIN_LIST, SKIN_RES_REGDATA, UP_PROPERTY, RES_REG_PROPS):
297    """ Register resources in portal's registry, remember existant settings."""
298    # Get original registered resources
299    portal_res_srings = []
300    for r in portal_res.getResources():
301        portal_res_srings.append(";".join(['%%s::%%s'%%(r[0],str(r[1])) \
302                                for r in getResourceProperties(r, RES_REG_PROPS)]))
303    addProperty(pp_up, UP_PROPERTY, portal_res_srings, 'lines', out)
304    # Tune Resource registry according to new skin needs
305    unexistent = [] # list of default resources,
306                    # which present in Skin-product, BUT absent in portal
307    portal_res_ids = portal_res.getResourceIds()
308    for res_dict in SKIN_RES_REGDATA:
309        if res_dict['id'] not in portal_res_ids:
310            # It's interesting - Resource Registry allow adding unexistent resource - use this
311            resRegisterFunction(**res_dict)
312            if res_dict['id'] not in RESOURCE_SKIN_LIST:
313                unexistent.append(res_dict['id'])
314        else:
315            pos = portal_res.getResourcePosition(res_dict['id'])
316            portal_res.unregisterResource(res_dict['id'])
317            resRegisterFunction(**res_dict)
318            portal_res.moveResource(res_dict['id'], pos)
319    if unexistent:
320        print >> out, "!!! - BAD: your Resource Regestry have'nt %%s resource(s), which may lead to some problems." %% unexistent
321
322def getVersion(res_list):
323    """Check version of skin product generator."""
324    return (res_list and not '::' in res_list[0] and '0.5') or '0.7'
325
326def uninstallResource(portal_res, original_res_list, RESOURCE_SKIN_LIST, resRegisterFunction):
327    # Prepare Resource Registry data for backup to original state
328    original_res_regestry = {}
329    genVersion = getVersion(original_res_list)
330    for rec in original_res_list:
331        resource = {}
332        if genVersion == '0.7':
333            [resource.update({prop.split('::')[0]:prop.split('::')[1]}) for prop in rec.split(";")]
334        elif genVersion == '0.5':
335            props = rec.split(";")
336            [resource.update({CSS_BASE_IDS_QPSD053[i]:props[i]}) for i in range(len(CSS_BASE_IDS_QPSD053))]
337        original_res_regestry[resource.pop('id')] = resource
338    # Work up actual Resource Registry
339    res_dict = portal_res.getResourcesDict()
340    for res_id in res_dict.keys():
341        # Remove from Resource Registry Skin product's resources
342        if res_id in RESOURCE_SKIN_LIST \
343           and res_id not in original_res_regestry.keys():
344            portal_res.unregisterResource(res_id)
345            continue
346        # Backup 'enabled' property Registry's resourses to it's original state
347        if original_res_regestry.has_key(res_id):
348            act_Enabled_state = res_dict[res_id].getEnabled()
349            orig_Enabled_state = original_res_regestry[res_id]['enabled']
350            if act_Enabled_state != orig_Enabled_state:
351                pos = portal_res.getResourcePosition(res_id)
352                resource = res_dict[res_id]
353                res = original_res_regestry[res_id]
354                portal_res.unregisterResource(res_id)
355                resRegisterFunction(res_id, **res)
356                portal_res.moveResource(res_id, pos)
357
358def customizeSlots(portal, pp_up, out):
359    # Get original Site's column lists
360    orig_left_slots = left_column = list(portal.left_slots)
361    orig_right_slots = right_column = list(portal.right_slots)
362    # Save original Site's LEFT and RIGHT slots
363    addProperty(pp_up, 'q_left_slots', orig_left_slots, 'lines', out)
364    addProperty(pp_up, 'q_right_slots', orig_right_slots, 'lines', out)
365    # blend-with-site - to portal's slots adding only new one from skin-porduct
366    # blend-with-skin - portal slots forming in the following manner:
367    #                   first adding skin-porduct's slots, than new one from portal
368    # replace - to portal's slots forming only from the skin-porduct's slot list
369    if SLOT_FORMING == "blend_with_skin":
370        left_column, right_column = formSlotsColumn(LEFT_SLOTS, RIGHT_SLOTS, 
371                                                    orig_left_slots, orig_right_slots, MAIN_COLUMN)
372    elif SLOT_FORMING == "blend_with_site":
373        left_column, right_column = formSlotsColumn(orig_left_slots, orig_right_slots,
374                                                    LEFT_SLOTS, RIGHT_SLOTS, MAIN_COLUMN )
375    elif SLOT_FORMING == "replace":
376        left_column, right_column = formSlotsColumn(LEFT_SLOTS, RIGHT_SLOTS, [], [], MAIN_COLUMN)
377    # REPLACE SITE's column slots
378    portal.left_slots = tuple(left_column)
379    portal.right_slots = tuple(right_column)
380    print >> out, "Complited portal slots customization ..."
381
382# main_column ("left" / "right" / "both") mean which of the MAIN column is favour
383def formSlotsColumn(main_left, main_right, slave_left=[], slave_right=[], main_column="both"):
384    result_left = main_left
385    result_right = main_right
386    if main_column == "left":
387    # 1) APPEND to MAIN_LEFT list *new for main_left column* slots from slave_left list
388    # 2) APPEND to MAIN_RIGHT list *new for both main columns* slots from slave_right
389    # 3) REMOVE slots from MAIN_RIGHT list, which are *doubled* in MAIN_LEFT
390        [result_left.append(slot) for slot in slave_left if slot not in result_left]
391        [result_right.append(slot) for slot in slave_right \
392                                   if slot not in result_right and slot not in result_left]
393        [result_right.remove(slot) for slot in result_left if slot in result_right]
394    elif main_column == "right":
395    # 1) APPEND to MAIN_LEFT list *new for main_right column* slots from slave_left list
396    # 2) APPEND to MAIN_RIGHT list *new for both main columns* slots from slave_right
397    # 3) REMOVE slots from MAIN_LEFT list, which are *doubled* in MAIN_RIGHT
398        [result_right.append(slot) for slot in slave_right if slot not in result_right]
399        [result_left.append(slot) for slot in slave_left \
400                                  if slot not in result_left and slot not in result_right]
401        [result_left.remove(slot) for slot in result_right if slot in result_left]
402    elif main_column == "both":
403    # 1) APPEND to MAIN_LEFT list *new for both main columns* slots from slave_left list
404    # 2) APPEND to MAIN_RIGHT list *new for both main columns* slots from slave_right
405        [result_left.append(slot) for slot in slave_left \
406                                  if slot not in result_left and slot not in result_right]
407        [result_right.append(slot) for slot in slave_right \
408                                   if slot not in result_right and slot not in result_left]
409    return [result_left, result_right]
410
411def getProperty(pp, ps, id, default=[]):
412    """ Get property from portal_properties/[property_sheet]"""
413    res = default
414    if ps in pp.objectIds() and pp[ps].hasProperty(id):
415        res = pp[ps].getProperty(id, default)
416    return res
Note: See TracBrowser for help on using the repository browser.