class PackagesStore(object): ''' Stores a list of L{cerbero.packages.package.Package} ''' PKG_EXT = '.package' def __init__(self, config, load=True): self._config = config self._packages = {} # package_name -> package self.cookbook = CookBook(config, load) # used in tests to skip loading a dir with packages definitions if not load: return if not os.path.exists(config.packages_dir): raise FatalError( _("Packages dir %s not found") % config.packages_dir) self._load_packages() def get_packages_list(self): ''' Gets the list of packages @return: list of packages @rtype: list ''' packages = self._packages.values() packages.sort(key=lambda x: x.name) return packages def get_package(self, name): ''' Gets a recipe from its name @param name: name of the package @type name: str @return: the package instance @rtype: L{cerbero.packages.package.Package} ''' if name not in self._packages: raise PackageNotFoundError(name) return self._packages[name] def get_package_deps(self, pkg, recursive=False): ''' Gets the dependencies of a package @param package: name of the package or package instance @type package: L{cerbero.packages.package.Package} @return: a list with the package dependencies @rtype: list ''' if isinstance(pkg, str): pkg = self.get_package(pkg) if isinstance(pkg, package.MetaPackage): ret = self._list_metapackage_deps(pkg) else: ret = [self.get_package(x) for x in pkg.deps] # get deps recursively if recursive: for p in ret: ret.extend(self.get_package_deps(p, recursive)) return remove_list_duplicates(ret) def get_package_files_list(self, name): ''' Gets the list of files provided by a package @param name: name of the package @type name: str @return: the package instance @rtype: L{cerbero.packages.package.PackageBase} ''' p = self.get_package(name) if isinstance(p, package.MetaPackage): return sorted(self._list_metapackage_files(p)) else: return sorted(p.files_list()) def add_package(self, package): ''' Adds a new package to the store @param package: the package to add @type package: L{cerbero.packages.package.PackageBase} ''' self._packages[package.name] = package def get_package_recipes_deps(self, package_name): ''' Gets the list of recipes needed to create this package @param name: name of the package @type name: str @return: a list with the recipes required to build this package @rtype: list ''' deps = self.get_package_deps(package_name) return [self.cookbok.get_recipe(x) for x in deps] def _list_metapackage_deps(self, metapackage): def get_package_deps(package_name, visited=[], depslist=[]): if package_name in visited: return visited.append(package_name) p = self.get_package(package_name) depslist.append(p) for p_name in p.deps: get_package_deps(p_name, visited, depslist) return depslist deps = [] for p in metapackage.list_packages(): deps.extend(get_package_deps(p, [], [])) return remove_list_duplicates(deps) def _list_metapackage_files(self, metapackage): l = [] for p in self._list_metapackage_deps(metapackage): l.extend(p.files_list()) # remove duplicates and sort return sorted(list(set(l))) def _load_packages(self): self._packages = {} packages = defaultdict(dict) repos = self._config.get_packages_repos() for reponame, (repodir, priority) in repos.iteritems(): packages[int(priority)].update( self._load_packages_from_dir(repodir)) # Add packages by ascending pripority for key in sorted(packages.keys()): self._packages.update(packages[key]) # Add a package for every recipe for recipe in self.cookbook.get_recipes_list(): if not recipe.allow_package_creation: continue p = self._package_from_recipe(recipe) if p.name in self._packages.keys(): m.warning( "Package with name '%s' already exists, not including it", p.name) else: self._packages[p.name] = p def _package_from_recipe(self, recipe): p = package.Package(self._config, self, self.cookbook) p.name = '%s-pkg' % recipe.name p.license = recipe.licenses if recipe.built_version(): version = recipe.built_version() else: version = recipe.version p.version = '%s-%s' % (version, self.cookbook.recipe_file_hash(recipe.name)) p.files = ['%s' % recipe.name] p.load_files() return p def _load_packages_from_dir(self, repo): packages_dict = {} packages = shell.find_files('*%s' % self.PKG_EXT, repo) packages.extend(shell.find_files('*/*%s' % self.PKG_EXT, repo)) for f in packages: p = self._load_package_from_file(f) if p is None: m.warning(_("Could not found a valid package in %s") % f) continue packages_dict[p.name] = p return packages_dict def _load_package_from_file(self, filepath): mod_name, file_ext = os.path.splitext(os.path.split(filepath)[-1]) try: d = { 'Platform': Platform, 'Architecture': Architecture, 'Distro': Distro, 'DistroVersion': DistroVersion, 'License': License, 'package': package, 'PackageType': PackageType } parse_file(filepath, d) if 'Package' in d: p = d['Package'](self._config, self, self.cookbook) elif 'SDKPackage' in d: p = d['SDKPackage'](self._config, self) elif 'InstallerPackage' in d: p = d['InstallerPackage'](self._config, self) elif 'App' in d: p = d['App'](self._config, self, self.cookbook) elif 'AppExtensionPackage' in d: p = d['AppExtensionPackage'](self._config, self, self.cookbook) else: raise Exception('Package, SDKPackage, InstallerPackage or App ' 'class not found') p.__file__ = os.path.abspath(filepath) p.prepare() # reload files from package now that we called prepare that # may have changed it p.load_files() return p except Exception, ex: import traceback traceback.print_exc() m.warning("Error loading package %s" % ex) return None
class PackagesStore (object): ''' Stores a list of L{cerbero.packages.package.Package} ''' PKG_EXT = '.package' def __init__(self, config, load=True): self._config = config self._packages = {} # package_name -> package self.cookbook = CookBook(config, load) # used in tests to skip loading a dir with packages definitions if not load: return if not os.path.exists(config.packages_dir): raise FatalError(_("Packages dir %s not found") % config.packages_dir) self._load_packages() def get_packages_list(self): ''' Gets the list of packages @return: list of packages @rtype: list ''' packages = self._packages.values() packages.sort(key=lambda x: x.name) return packages def get_package(self, name): ''' Gets a recipe from its name @param name: name of the package @type name: str @return: the package instance @rtype: L{cerbero.packages.package.Package} ''' if name not in self._packages: raise PackageNotFoundError(name) return self._packages[name] def get_package_deps(self, pkg, recursive=False): ''' Gets the dependencies of a package @param package: name of the package or package instance @type package: L{cerbero.packages.package.Package} @return: a list with the package dependencies @rtype: list ''' if isinstance(pkg, str): pkg = self.get_package(pkg) if isinstance(pkg, package.MetaPackage): ret = self._list_metapackage_deps(pkg) else: ret = [self.get_package(x) for x in pkg.deps] # get deps recursively if recursive: for p in ret: ret.extend(self.get_package_deps(p, recursive)) return remove_list_duplicates(ret) def get_package_files_list(self, name): ''' Gets the list of files provided by a package @param name: name of the package @type name: str @return: the package instance @rtype: L{cerbero.packages.package.PackageBase} ''' p = self.get_package(name) if isinstance(p, package.MetaPackage): return sorted(self._list_metapackage_files(p)) else: return sorted(p.files_list()) def add_package(self, package): ''' Adds a new package to the store @param package: the package to add @type package: L{cerbero.packages.package.PackageBase} ''' self._packages[package.name] = package def get_package_recipes_deps(self, package_name): ''' Gets the list of recipes needed to create this package @param name: name of the package @type name: str @return: a list with the recipes required to build this package @rtype: list ''' deps = self.get_package_deps(package_name) return [self.cookbok.get_recipe(x) for x in deps] def _list_metapackage_deps(self, metapackage): def get_package_deps(package_name, visited=[], depslist=[]): if package_name in visited: return visited.append(package_name) p = self.get_package(package_name) depslist.append(p) for p_name in p.deps: get_package_deps(p_name, visited, depslist) return depslist deps = [] for p in metapackage.list_packages(): deps.extend(get_package_deps(p, [], [])) return remove_list_duplicates(deps) def _list_metapackage_files(self, metapackage): l = [] for p in self._list_metapackage_deps(metapackage): l.extend(p.files_list()) # remove duplicates and sort return sorted(list(set(l))) def _load_packages(self): self._packages = {} packages = defaultdict(dict) repos = self._config.get_packages_repos() for reponame, (repodir, priority) in repos.iteritems(): packages[int(priority)].update( self._load_packages_from_dir(repodir)) # Add packages by ascending pripority for key in sorted(packages.keys()): self._packages.update(packages[key]) # Add a package for every recipe for recipe in self.cookbook.get_recipes_list(): if not recipe.allow_package_creation: continue p = self._package_from_recipe(recipe) if p.name in self._packages.keys(): m.warning("Package with name '%s' already exists, not including it", p.name) else: self._packages[p.name] = p def _package_from_recipe(self, recipe): p = package.Package(self._config, self, self.cookbook) p.name = '%s-pkg' % recipe.name p.license = recipe.licenses if recipe.built_version(): version = recipe.built_version() else: version = recipe.version p.version = '%s-%s' % (version, self.cookbook.recipe_file_hash(recipe.name)) p.files = ['%s' % recipe.name] p.load_files() return p def _load_packages_from_dir(self, repo): packages_dict = {} packages = shell.find_files('*%s' % self.PKG_EXT, repo) packages.extend(shell.find_files('*/*%s' % self.PKG_EXT, repo)) for f in packages: p = self._load_package_from_file(f) if p is None: m.warning(_("Could not found a valid package in %s") % f) continue packages_dict[p.name] = p return packages_dict def _load_package_from_file(self, filepath): mod_name, file_ext = os.path.splitext(os.path.split(filepath)[-1]) try: d = {'Platform': Platform, 'Architecture': Architecture, 'Distro': Distro, 'DistroVersion': DistroVersion, 'License': License, 'package': package, 'PackageType': PackageType} parse_file(filepath, d) if 'Package' in d: p = d['Package'](self._config, self, self.cookbook) elif 'SDKPackage' in d: p = d['SDKPackage'](self._config, self) elif 'InstallerPackage' in d: p = d['InstallerPackage'](self._config, self) elif 'App' in d: p = d['App'](self._config, self, self.cookbook) elif 'AppExtensionPackage' in d: p = d['AppExtensionPackage'](self._config, self, self.cookbook) else: raise Exception('Package, SDKPackage, InstallerPackage or App ' 'class not found') p.__file__ = os.path.abspath(filepath) p.prepare() # reload files from package now that we called prepare that # may have changed it p.load_files() return p except Exception, ex: import traceback traceback.print_exc() m.warning("Error loading package %s" % ex) return None