Package application :: Module Parcel
[hide private]
[frames] | no frames]

Source Code for Module application.Parcel

  1  #   Copyright (c) 2004-2007 Open Source Applications Foundation 
  2  # 
  3  #   Licensed under the Apache License, Version 2.0 (the "License"); 
  4  #   you may not use this file except in compliance with the License. 
  5  #   You may obtain a copy of the License at 
  6  # 
  7  #       http://www.apache.org/licenses/LICENSE-2.0 
  8  # 
  9  #   Unless required by applicable law or agreed to in writing, software 
 10  #   distributed under the License is distributed on an "AS IS" BASIS, 
 11  #   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
 12  #   See the License for the specific language governing permissions and 
 13  #   limitations under the License. 
 14   
 15   
 16  __parcel__ = "//Schema/Core" 
 17   
 18  import sys, os, logging 
 19  from datetime import datetime 
 20   
 21  import schema, pkg_resources 
 22  from pkg_resources import working_set 
 23  import application.Globals as Globals 
 24   
 25  logger = logging.getLogger(__name__) 
 26   
27 -def activate_plugins(dirs, working_set=working_set):
28 """ 29 Add plugins from `dirs` to `working_set` 30 """ 31 plugin_env = pkg_resources.Environment(dirs) 32 dists, errors = working_set.find_plugins(plugin_env, fallback=False) 33 map(working_set.add, dists)
34 # XXX log errors 35
36 -def loadable_parcels(working_set=working_set, env=None, installer=None):
37 """ 38 Yield entry points for loadable parcels in `working_set` 39 """ 40 for ep in working_set.iter_entry_points('chandler.parcels'): 41 try: 42 ep.require(env, installer) 43 except pkg_resources.ResolutionError: 44 # XXX log the error 45 continue # skip unloadable parcels ??? 46 else: 47 yield ep
48
49 -def load_parcel_from_entrypoint(rv,ep):
50 """ 51 Load the parcel defined by entrypoint `ep` into repository view `rv` 52 53 `ep` should be an entry point yielded by ``loadable_parcels()``, and `rv` 54 should be a repository view. The egg corresponding to the entry point, 55 along with any dependencies, must already be on sys.path. 56 57 If a parcel already exists in `rv` for the entrypoint, it is updated if 58 its version doesn't match the version of the egg containing the 59 entry point. If no parcel exists, it is created. 60 """ 61 module_name = ep.module_name 62 egg_version = ep.dist.version 63 64 if ep.attrs: 65 # This is a fatal error so that nobody will ship 66 # a parcel with attrs set to something! 67 raise AssertionError( 68 "%s: parcel entrypoints must specify a module only" 69 % ep.dist 70 ) 71 72 old_parcel = find_parcel_from_entrypoint(rv,ep) 73 74 if old_parcel is None: 75 new_parcel = schema.parcel_for_module(module_name, rv) 76 old_version = egg_version 77 else: 78 new_parcel = old_parcel 79 old_version = getattr(old_parcel,'version','') 80 81 #new_parcel.egg_id = ep.dist.key XXX schema change needed for this 82 new_parcel.version = egg_version 83 84 # XXX what if parcel came from a different egg? 85 86 if old_version <> egg_version: 87 schema.synchronize(rv, module_name) # get any new Kinds 88 module = sys.modules[module_name] # get the actual module 89 if hasattr(module,'installParcel') and not hasattr(module,'__parcel__'): 90 module.installParcel(new_parcel, old_version) # upgrade! 91 92 return new_parcel
93 94
95 -def find_parcel_from_entrypoint(rv,ep):
96 """ 97 Find the parcel item defined by entrypoint `ep` into repository view `rv` 98 99 `ep` should be an entry point yielded by ``loadable_parcels()``, and `rv` 100 should be a repository view. 101 102 Return `None` if it doesn't exist. 103 """ 104 105 return rv.findPath('//parcels/'+ep.module_name.replace('.','/'))
106 107 108 #@@@Temporary testing tool written by Morgen -- DJA 109 timing = False 110 if timing: import util.timing 111
112 -class Manager(schema.Item):
113 """ 114 To use the parcel manager, retrieve an instance of it by using the class 115 method get():: 116 117 import application 118 mgr = application.Parcel.Manager.get(view, path=parcelSearchPath) 119 mgr.loadParcels() 120 121 if "path" is not passed in, it will use 122 os.path.join(Globals.chandlerDirectory, "parcels"). 123 """ 124 125 # The path attribute contains the path in bytes. These bytes 126 # may be 8bit with a filesystem encoding or may be 127 # 7bit ascii 128 path = schema.Sequence(schema.Bytes, initialValue = []) 129 130 @classmethod
131 - def get(cls, view, path=None):
132 """ 133 Class method for getting an instance of the parcel manager. 134 135 If there is a manager item already already in this repository, that 136 will be returned. Otherwise one will be created. 137 138 @param view: The repository view object to load items into. 139 @type view: L{repository.persistence.RepositoryView} 140 @param path: The search path for finding parcels. This is a list 141 of absolute directory paths; when loading parcels, each directory 142 in the search path will be used as a starting point for recursively 143 finding parcel.xml files. 144 @type path: list 145 @return: parcel manager object 146 """ 147 148 parcelRoot = view.findPath("//parcels") 149 if parcelRoot is None: 150 parcelRoot = Parcel("parcels",view) 151 152 manager = view.findPath("//parcels/manager") 153 if manager is None: 154 manager = Manager("manager", parcelRoot) 155 156 if not path: 157 path = [os.path.join(Globals.chandlerDirectory, "parcels")] 158 159 if manager.path != path: 160 manager.path = path 161 162 return manager
163 164
165 - def __syncParcel(self, pkg):
166 """ 167 Synchronize the specified parcel's Python schema with self.repo 168 169 This will import the corresponding Python module and synchronize its 170 schema with the repository. If the imported module has a parent 171 module that has not yet been synchronized, this method will load 172 the parent parcel, thereby synchronizing the parent module first. 173 """ 174 if pkg in self._imported: 175 return # skip already-processed parcels 176 else: 177 self._imported.add(pkg) 178 179 if '.' in pkg: 180 # load parent first - even though schema API does this too, 181 # the parcel loader will get confused and not load the 182 # parent parcel correctly, unless we process it here. :( 183 parent_pkg = pkg.rsplit('.',1)[0] 184 if parent_pkg not in self._imported: 185 self.__syncParcel(parent_pkg) 186 187 # Last, but not least, actually synchronize the package 188 schema.synchronize(self.itsView, pkg)
189 190
191 - def findPlugins(self):
192 """ 193 Yield top-level parcels 194 """ 195 from glob import glob 196 for directory in self.path: 197 for initfile in glob(os.path.join(directory,'*','__init__.py')): 198 yield os.path.basename(os.path.dirname(initfile))
199 200
201 - def loadParcels(self, namespaces=None):
202 """ 203 Load parcel items into the repository. 204 205 The namespaces passed in via the namespaces parameter (a list) are 206 then loaded into the repository. If that parameter is None, then all 207 parcels are loaded. 208 209 @param namespaces: The list of namespaces to load 210 @type namespaces: list of strings 211 """ 212 #@@@Temporary testing tool written by Morgen -- DJA 213 if timing: util.timing.begin("Load parcels") 214 215 self._imported = set() # imported namespaces 216 217 load_plugins = not namespaces 218 219 if not namespaces: 220 namespaces = sorted(self.findPlugins()) 221 appParcel = getattr( 222 getattr(Globals,'options',None), "appParcel", "osaf.app" 223 ) 224 # always load the app parcel first 225 namespaces.insert(0, appParcel) 226 227 logger.info("Loading parcels...") 228 229 # Load old-style or explicitly-listed parcels 230 for namespace in namespaces: 231 self.__syncParcel(namespace) 232 233 if load_plugins: 234 # Load egg and plugin parcels 235 for parcel_ep in loadable_parcels(): 236 load_parcel_from_entrypoint(self.itsView, parcel_ep) 237 238 logger.info("...done") 239 240 #@@@Temporary testing tool written by Morgen -- DJA 241 if timing: util.timing.end("Load parcels")
242 243 #if self.itsView._schema_init_level or self.itsView._schema_init_queue: 244 # raise AssertionError("Incomplete initialization") 245 246 247 # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 248
249 -class Parcel(schema.Item):
250 """ 251 The parcel item class. 252 """ 253 author = schema.One(schema.Text) 254 publisher = schema.One(schema.Text) 255 status = schema.One(schema.Text) 256 summary = schema.One(schema.Text) 257 icon = schema.One(schema.Text) 258 version = schema.One(schema.Text) 259 createdOn = schema.One(schema.DateTime) 260 modifiedOn = schema.One(schema.DateTime) 261 namespace = schema.One(schema.Text, defaultValue = u'') 262 namespaceMap = schema.Mapping(schema.Text, initialValue = {}) 263 file = schema.One(schema.Text, initialValue = u'') 264 originalValues = schema.Mapping(schema.Dictionary, initialValue = {}) 265
266 - def __setup__(self):
267 self.modifiedOn = self.createdOn = datetime.now()
268 269 270 # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 271
272 -class Reference(schema.Item):
273 item = schema.One( 274 schema.Item, 275 initialValue = None, 276 otherName = 'references' 277 )
278 279 # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 280