def __run_search(paths, api_inst): """Function which interfaces with the search engine and extracts the fmri and variants from the actions which deliver the paths being searched for. 'paths' is the paths to search for. 'api_inst' is an ImageInterface which references the current image.""" qs = [ api.Query(p, case_sensitive=False, return_actions=True) for p in paths ] search_res = api_inst.local_search(qs) res = [] try: for num, pub, (version, return_type, (pfmri, match, a_str)) \ in search_res: pfmri = fmri.PkgFmri(pfmri) m = api_inst.img.get_manifest(pfmri) vars = variants.VariantSets( actions.fromstr(a_str.rstrip()).get_variants()) vars.merge_unknown(m.get_all_variants()) res.append((pfmri, vars)) except api_errors.SlowSearchUsed: pass return res
def __init__(self, action, pkg_vars, proto_dir, attrs): """Each dependency needs to know the action that generated it and the variants for the package containing that action. 'action' is the action which produced this dependency. 'pkg_vars' is the list of variants against which the package delivering the action was published. 'proto_dir' is the proto area where the file the action delivers lives. 'attrs' is a dictionary to containing the relevant action tags for the dependency. """ self.action = action self.pkg_vars = pkg_vars self.proto_dir = proto_dir self.dep_vars = variant.VariantSets(action.get_variants()) attrs.update([("fmri", self.DUMMY_FMRI), ("type", self.DEPEND_TYPE), ("%s.reason" % self.DEPEND_DEBUG_PREFIX, self.action_path())]) if self.dep_vars is not None: attrs.update(self.dep_vars) depend.DependencyAction.__init__(self, **attrs)
def get_var_diff(self, ext_vars): """Find the difference of the set of variants declared for the action that produced this dependency, and another set of variants.""" vars = variant.VariantSets(self.action.get_variants()) for k in self.pkg_vars: if k not in vars: vars[k] = self.pkg_vars[k] return vars.difference(ext_vars)
def resolve_internal_deps(deps, mfst, proto_dirs, pkg_vars): """Given a list of dependencies, remove those which are satisfied by others delivered by the same package. 'deps' is a list of Dependency objects. 'mfst' is the Manifest of the package that delivered the dependencies found in deps. 'proto_dir' is the path to the proto area which holds the files that will be delivered by the package. 'pkg_vars' are the variants that this package was published against.""" res = [] delivered = {} delivered_bn = {} for a in mfst.gen_actions_by_type("file"): pvars = variants.VariantSets(a.get_variants()) if not pvars: pvars = pkg_vars else: pvars.merge_unknown(pkg_vars) p = a.attrs["path"] delivered.setdefault(p, variants.VariantSets()).merge(pvars) p = os.path.join(a.attrs[portable.PD_PROTO_DIR], p) np = os.path.normpath(p) rp = os.path.realpath(p) # adding the normalized path delivered.setdefault(np, variants.VariantSets()).merge(pvars) # adding the real path delivered.setdefault(rp, variants.VariantSets()).merge(pvars) bn = os.path.basename(p) delivered_bn.setdefault(bn, variants.VariantSets()).merge(pvars) for d in deps: etype, pvars = d.resolve_internal(delivered_files=delivered, delivered_base_names=delivered_bn) if etype is None: continue d.dep_vars = pvars res.append(d) return res
def split_off_variants(dep, pkg_vars): """Take a dependency which may be tagged with variants and move those tags into a VariantSet.""" dep_vars = variants.VariantSets(dep.get_variants()) dep_vars.merge_unknown(pkg_vars) # Since all variant information is being kept in the above VariantSets, # remove the variant information from the action. This prevents # confusion about which is the authoritative source of information. dep.strip_variants() return dep, dep_vars
def resolve_deps(manifest_paths, api_inst): """For each manifest given, resolve the file dependencies to package dependencies. It returns a mapping from manifest_path to a list of dependencies and a list of unresolved dependencies. 'manifest_paths' is a list of paths to the manifests being resolved. 'api_inst' is an ImageInterface which references the current image.""" manifests = [(mp, choose_name(mp, mfst), mfst, mfst.get_all_variants()) for mp, mfst in ((mp, make_manifest(mp)) for mp in manifest_paths)] delivered_files = {} # Build a list of all files delivered in the manifests being resolved. for n, f_list, pkg_vars in ((name, itertools.chain( mfst.gen_actions_by_type("file"), mfst.gen_actions_by_type("hardlink"), mfst.gen_actions_by_type("link")), pv) for mp, name, mfst, pv in manifests): for f in f_list: dep_vars = variants.VariantSets(f.get_variants()) dep_vars.merge_unknown(pkg_vars) delivered_files.setdefault(f.attrs["path"], []).append( (n, dep_vars)) pkg_deps = {} errs = [] for mp, name, mfst, pkg_vars in manifests: if mfst is None: pkg_deps[mp] = None continue pkg_res = [(d, find_package(api_inst, delivered_files, d, pkg_vars)) for d in mfst.gen_actions_by_type("depend") if is_file_dependency(d)] deps = [] for file_dep, (res, dep_vars) in pkg_res: if not res: dep_vars.merge_unknown(pkg_vars) errs.append((mp, file_dep, dep_vars)) else: deps.extend(res) if not dep_vars.is_satisfied(): errs.append((mp, file_dep, dep_vars)) pkg_deps[mp] = deps return pkg_deps, errs
def add_fmri_path_mapping(pathdict, pfmri, mfst): """Add mappings from path names to FMRIs and variants. 'pathdict' is a dict path -> (fmri, variants) to which entries are added. 'pfmri' is the FMRI of the current manifest 'mfst' is the manifest to process.""" pvariants = mfst.get_all_variants() for f in itertools.chain(mfst.gen_actions_by_type("file"), mfst.gen_actions_by_type("hardlink"), mfst.gen_actions_by_type("link")): dep_vars = variants.VariantSets(f.get_variants()) dep_vars.merge_unknown(pvariants) pathdict.setdefault(f.attrs["path"], []).append( (pfmri, dep_vars))
def find_package(api_inst, delivered, file_dep, pkg_vars): """Find the packages which resolve the dependency. It returns a list of dependency actions with the fmri tag resolved. 'api_inst' is an ImageInterface which references the current image. 'delivered' is a dictionary mapping paths to a list of fmri, variants pairs. 'file_dep' is the dependency being resolved. "pkg_vars' is the variants against which the package was published.""" dep_vars = variants.VariantSets(file_dep.get_variants()) dep_vars.merge_unknown(pkg_vars) res, dep_vars = \ find_package_using_delivered_files(delivered, file_dep, dep_vars, pkg_vars) if res and dep_vars.is_satisfied(): return res, dep_vars search_res, dep_vars = \ find_package_using_search(api_inst, file_dep, dep_vars, pkg_vars) res.extend(search_res) return res, dep_vars
def get_var_set(self): vars = variant.VariantSets(self.action.get_variants()) for k in self.pkg_vars: if k not in vars: vars[k] = self.pkg_vars[k] return vars
def get_all_variants(self): """Return a dictionary mapping variant tags to their values.""" return variant.VariantSets( dict(((name, self.attributes[name]) for name in self.attributes if name.startswith("variant."))))
def get_variants(self): return variant.VariantSets( dict(((v, self.attrs[v]) for v in self.get_varcet_keys()[0])))