def loadTables(self, productName=None, flavors=None): """ ensure all tables for a given product have been parsed and cached into memory. @param productName the name of the product to cache tables for. If None, cache for all products @param flavors the flavors of products to cache tables fo. """ if productName and utils.is_string(productName): productName = productName.split() if not flavors: flavors = self.getFlavors() elif utils.is_string(flavors): flavors = flavors.split() for flavor in flavors: if flavor not in self.lookup: continue names = productName if not productName: names = self.getProductNames(flavor) for name in names: try: self.lookup[flavor][name].loadTables() except KeyError: pass
def getChainFile(self, tag, productName, searchUserDB=False): """ return the ChainFile for the version name of the product that has the given tag assigned to it. None is return if the tag is not assigned to any version. ProductNotFound is raised if no version of the product is declared. @param tag the string name for the tag. A user tag must be prepended by a "user:"******""" pdir = self._productDir(productName) if not os.path.exists(pdir): raise ProductNotFound(productName, stack=self.dbpath) if is_string(tag): tag = eups.tags.Tag(tag) pdirs = [] if searchUserDB and tag.isUser(): for d in self._getUserTagDb(values=True): if d: pdirs.append(self._productDir(productName, d)) else: pdirs.append(pdir) for pdir in pdirs: tfile = self._tagFileInDir(pdir, tag.name) if os.path.exists(tfile): return ChainFile(tfile) return None
def getChainFile(self, tag, productName, searchUserDB=False): """ return the ChainFile for the version name of the product that has the given tag assigned to it. None is return if the tag is not assigned to any version. ProductNotFound is raised if no version of the product is declared. @param tag the string name for the tag. A user tag must be prepended by a "user:"******""" pdir = self._productDir(productName) if not os.path.exists(pdir): raise ProductNotFound(productName, stack=self.dbpath); if is_string(tag): tag = eups.tags.Tag(tag) pdirs = [] if searchUserDB and tag.isUser(): for d in self._getUserTagDb(values=True): if d: pdirs.append(self._productDir(productName, d)) else: pdirs.append(pdir) for pdir in pdirs: tfile = self._tagFileInDir(pdir, tag.name) if os.path.exists(tfile): return ChainFile(tfile) return None
def assignTag(self, tag, productName, version, flavors=None, writeableDB=None): """ assign a tag to a given product. @param tag : the name of the tag to assign. If the name is prepended with the "user:"******""" if is_string(tag): tag = eups.tags.Tag(tag) vf = VersionFile(self._versionFile(productName, version)) declaredFlavors = vf.getFlavors() if len(declaredFlavors) == 0: raise ProductNotFound(productName, version) if flavors is None: flavors = list(declaredFlavors) elif not isinstance(flavors, list): flavors = [flavors] else: flavors = list(flavors) # make a copy; we're gonna mess with it if len(flavors) == 0: flavors = list(declaredFlavors) # reduce the list of flavors to ones actually declared for i in xrange(len(flavors)): flavor = flavors.pop(0) if flavor in declaredFlavors and flavor not in flavors: flavors.append(flavor) if len(flavors) == 0: raise ProductNotFound(productName, version, msg="Requested flavors not declared for %s %s" % (productName, version)) if not writeableDB and tag.isUser(): if not self._getUserTagDb(): raise RuntimeError("Unable to assign user tags (user db not available)") writeableDB = self._getUserTagDb() if writeableDB: pdir = self._productDir(productName, writeableDB) if not os.path.exists(pdir): os.makedirs(pdir) else: pdir = self._productDir(productName) tfile = self._tagFileInDir(pdir, tag.name) tagFile = ChainFile(tfile, productName, tag.name) tagFile.setVersion(version, flavors) tagFile.write()
def cacheIsInSync(self, flavors=None): """ return False if it appears that disk caches have been updated since they were last read in. Note that this is different from cacheIsUpToDate() """ if not flavors: flavors = self.getFlavors() if utils.is_string(flavors): flavors = [flavors] for flavor in flavors: file = self._persistPath(flavor) if not self._cacheFileIsInSync(file): return False return True
def checkInit(self, forserver=True): """Check that self is properly initialised; this matters for subclasses with special needs""" if not eupsDistrib.Distrib.checkInit(self, forserver): return False if forserver: if 'pacmanCache' not in self.options: print("Option 'pacmanCache' not set", file=self.log) return False msg = "Illegal value for Option 'pacmanCache': " if not utils.is_string(self.options['pacmanCache']): print(msg + self.options['pacmanCache'], file=self.log) return False self.options['pacmanCache'] = self.options['pacmanCache'].strip() if len(self.options['pacmanCache']) == 0: print(msg + self.options['pacmanCache'], file=self.log) return False return True
def __init__(self, eupsenv, pkgroot, flavor=None, options=None, distFactory=None, verbosity=0, log=sys.stderr): """ create a Repository for a given server base URL (pkgroot) @param eupsenv the Eups controller instance to use @param pkgroot the base URL for the package server to pull packages from or deploy packages to. @param flavor the platform flavor of interest. #--CUT When installing packages, this value is ignored and the version set in the Eups controller is assumed to be the target platform. For all other actions (creating server packages, listing available packages), this value will be assumed. #-- If None or "generic", then a generic platform is assumed. @param options a dictionary of options to pass to Distrib instances used to install and create packages @param distFactory a DistFactory instance to use. If not provided a default one is created. @param verbosity if > 0, print status messages; the higher the number, the more messages that are printed (default=0). @param log the destination for status messages (default: sys.stderr) """ self.eups = eupsenv if not flavor: flavor = self.eups.flavor self.flavor = flavor self.distFactory = None if distFactory: self.distFactory = distFactory.clone() self.options = options self.verbose = verbosity if not isinstance(self.verbose, int): self.verbose = 0 self.log = log self.distServer = None if self.options is None: self.options = {} if not isinstance(self.options, dict): raise RuntimeError("Non-dictionary passed to options parameter: " + repr(self.options)) self.pkgroot = pkgroot if pkgroot: override = None if 'serverconf' in self.options: override = options['serverconf'] self.distServer = ServerConf.makeServer(pkgroot, eupsenv=eupsenv, override=override, verbosity=self.verbose, log=self.log) if self.distFactory is None: self.distFactory = DistribFactory(self.eups, self.distServer) elif not self.distServer: self.distFactory.resetDistribServer(self.distServer) # a cache of the supported tag names self._supportedTags = None # a cache of supported packages self._pkgList = None # True if servers should always be queried when looking for a # repository to get a package from. If False, an internal cache # of available products will be used. self._alwaysQueryServer = False if "alwaysQueryServer" in self.options: if is_string(self.options["alwaysQueryServer"]): self.options["alwaysQueryServer"] = \ self.options["alwaysQueryServer"].upper() if "TRUE".startswith(self.options["alwaysQueryServer"]): self.options["alwaysQueryServer"] = True else: self.options["alwaysQueryServer"] = False if self.options["alwaysQueryServer"]: self._alwaysQueryServer = True if self.distServer is not None and self.distServer.NOCACHE: self._alwaysQueryServer = True
def listPackages(self, product=None, version=None, flavor=None, tag=None, queryServer=None, noaction=False): """ return a list of available products on the server. Each item in the list is a list of the form, (product, version, flavor). The optional inputs will restrict the list to those matching the values. @param product the name of the product. If None, all available products are returned. @param version the desired version. This can either be a version version string or an instance of Tag. If None, all available versions are returned. @param flavor the desired platform flavor. If None, all available versions are returned. @param tag list only products matching this tag. If version is also specified, an empty list will be returned if the version (or matching versions) is (are) not assigned this tag. @param queryServer if True, this will force a query to the repository server. If False, an internal cache will be used if possible. If None (default), the behavior is controlled by the "alwaysQueryServer" passed to the constructor of this Repository (which defaults to False). """ if queryServer is None: queryServer = self._alwaysQueryServer if isinstance(version, Tag) and version.name != "latest": tag = version version = None if queryServer or tag: if self.distServer is None: raise RuntimeError("No distribution server set") if tag: if isinstance(tag, Tag): tagName = tag.name else: tagName = tag tag = self.eups.tags.getTag(tag) if not tag.isGlobal(): raise TagNotRecognized(tagName, "global", msg="Non-global tag \"%s\" requested." % tagName) if tagName == "latest": return self._listLatestProducts(product, flavor) if tagName not in self.getSupportedTags(): raise TagNotRecognized(tag, "global", msg="tag %s not supported by server" % tag) return self.distServer.listAvailableProducts(product, version, flavor, tagName) else: if self._pkgList is None: self._pkgList = self._getPackageLookup() out = [] prods = self._pkgList["_sortOrder"] if product: if product not in self._pkgList: return [] prods = [product] for prod in prods: flavs = self._pkgList[prod]["_sortOrder"] if flavor: if flavor not in self._pkgList[prod]: continue flavs = [flavor] for flav in flavs: if version is None: out.extend( (prod, v, flav) for v in self._pkgList[prod][flav] ) elif version and is_string(version): if version not in self._pkgList[prod][flav]: continue out.append( (prod, version, flav) ) else: # looking for latest out.append((prod,self._pkgList[prod][flav][-1],flav)) return out
def assignTag(self, tag, productName, version, flavors=None, writeableDB=None): """ assign a tag to a given product. @param tag : the name of the tag to assign. If the name is prepended with the "user:"******""" if is_string(tag): tag = eups.tags.Tag(tag) vf = VersionFile(self._versionFile(productName, version)) declaredFlavors = vf.getFlavors() if len(declaredFlavors) == 0: raise ProductNotFound(productName, version) if flavors is None: flavors = list(declaredFlavors) elif not isinstance(flavors, list): flavors = [flavors] else: flavors = list(flavors) # make a copy; we're gonna mess with it if len(flavors) == 0: flavors = list(declaredFlavors) # reduce the list of flavors to ones actually declared for i in xrange(len(flavors)): flavor = flavors.pop(0) if flavor in declaredFlavors and flavor not in flavors: flavors.append(flavor) if len(flavors) == 0: raise ProductNotFound( productName, version, msg="Requested flavors not declared for %s %s" % (productName, version)) if not writeableDB and tag.isUser(): if not self._getUserTagDb(): raise RuntimeError( "Unable to assign user tags (user db not available)") writeableDB = self._getUserTagDb() if writeableDB: pdir = self._productDir(productName, writeableDB) if not os.path.exists(pdir): os.makedirs(pdir) else: pdir = self._productDir(productName) tfile = self._tagFileInDir(pdir, tag.name) tagFile = ChainFile(tfile, productName, tag.name) tagFile.setVersion(version, flavors) tagFile.write()
def __init__(self, pkgroots, options=None, eupsenv=None, installFlavor=None, distribClasses=None, override=None, allowEmptyPkgroot=False, verbosity=None, log=sys.stderr): """ @param pkgroots the base URLs for the distribution repositories. This can either be a list or a pipe-delimited ("|") string. @param options a dictionary of named options that are used to fine- tune the behavior of the repositories. These are passed onto the constructors for the underlying Reposistory classes. @param eupsenv an instance of a Eups class containing the Eups environment to assume @param installFlavor the desired flavor any install requests @param distribClasses a dictionary by name of the Distrib classes to support. This will augmented by those specified by a server. @param override a dictionary of server configuration parameters that should override the configuration received from each server. @param allowEmptyPkgroot we are creating a distribution, so it's OK for pkgroot to be empty @param verbosity if > 0, print status messages; the higher the number, the more messages that are printed (default is the value of eupsenv.verbose). @param log the destination for status messages (default: sys.stderr) """ if utils.is_string(pkgroots): pkgroots = [p.strip() for p in pkgroots.split("|")] if not allowEmptyPkgroot and len(pkgroots) == 0: raise EupsException("No package servers to query; set -r or $EUPS_PKGROOT") # the Eups environment self.eups = eupsenv if not self.eups: self.eups = Eups() self.verbose = verbosity if self.verbose is None: self.verbose = self.eups.verbose self.log = log if self.log is None: self.log = sys.stdout if not distribClasses: distribClasses = {} # the list of repository base URLs self.pkgroots = [] # a lookup of Repository instances by its base URL self.repos = {} # the preferred installation flavor self.flavor = installFlavor if not self.flavor: self.flavor = self.eups.flavor df = DistribFactory(self.eups) for name in distribClasses.keys(): # note: this will override the server's recommendation # if we want change this, use: # if not df.supportsName(name): # df.register(distribClasses[name], name) # df.register(distribClasses[name], name) for pkgroot in pkgroots: # if pkgroot == None: # ds = None # else: # ds = ServerConf.makeServer(pkgroot, eupsenv=eupsenv, # override=override, # verbosity=self.eups.verbose) # try: dist = Repository(self.eups, pkgroot, options=options, flavor=installFlavor, distFactory=df, verbosity=self.eups.verbose) self.pkgroots += [pkgroot] self.repos[pkgroot] = dist except ImportError as e: msg = "Unable to use server %s: \"%s\"" % (pkgroot, e) if self.eups.force: print(msg + "; continuing", file=self.log) else: raise RuntimeError(msg + ". Remove server from PKGROOT or use force") if len(self.pkgroots) == 0: msg = "No usable package repositories are loaded" if allowEmptyPkgroot or self.eups.force: print("WARNING: %s" % msg, file=self.log) else: raise RuntimeError(msg) # a cache of the union of tag names supported by the repositories self._supportedTags = None # used by install() to control repeated error messages self._msgs = {}
def install(self, product, version=None, updateTags=None, alsoTag=None, depends=DEPS_ALL, noclean=False, noeups=False, options=None, manifest=None, searchDep=None): """ Install a product and all its dependencies. @param product the name of the product to install @param version the desired version of the product. This can either be a version string or an instance of Tag. If not provided (or None) the most preferred version will be installed. @param updateTags when None (default), server-assigned tags will be updated for this product and all its dependcies to match those recommended on the server (even if a product is already installed); otherwise it's the name of the tag that should be updated (so e.g. '' => none) @param alsoTag A list of tags to assign to all installed products (in addition to server tags). This can either be a space-delimited list, a list of string names, a Tag instance, or a list of Tag instances. @param depends If DEPS_ALL, product and dependencies will be installed DEPS_NONE, dependencies will not be installed DEPS_ONLY, only dependencies will be installed, usefull for developement purpose (before a setup -r .) @param noclean If False (default), the build directory will get cleaned up after a successful install. A True value prevents this. @param noeups if False (default), needed products that are already installed will be skipped over. If True, an attempt is made to install them anyway. This allows a product to be installed in the target install stack even if it is available in another stack managed by EUPS. Note, however, that if a needed product is already installed into the target stack, the installation may fail. Use with caution. @param options a dictionary of named options that are used to fine- tune the behavior of this Distrib class. See discussion above for a description of the options supported by this implementation; sub-classes may support different ones. @param manifest use this manifest (a local file) as the manifest for the requested product instead of downloading manifest from the server. @param searchDep if False, install will be prevented from recursively looking for dependencies of dependencies listed in manifests. In this case, it is assumed that a manifest contains all necessary dependencies. If True, the distribution identifiers in the manifest file are ignored and the dependencies will always be recursively searched for. If None, the choice to recurse is left up to the server where the manifest comes from (which usually defaults to False). """ if alsoTag is not None: if utils.is_string(alsoTag): alsoTag = [self.eups.tags.getTag(t) for t in alsoTag.split()] elif isinstance(alsoTag, Tag): alsoTag = [alsoTag] pkg = self.findPackage(product, version) if not pkg: raise ProductNotFound(product, version, msg="Product %s %s not found in any package repository" % (product, version)) (product, version, flavor, pkgroot) = pkg productRoot = self.getInstallRoot() if productRoot is None: raise EupsException("Unable to find writable place to install in EUPS_PATH") if manifest is not None: if not manifest or os.path.exists(manifest): raise EupsException("%s: user-provided manifest not found" % manifest) man = Manifest.fromFile(manifest, self.eups, verbosity=self.eups.verbose-1) else: man = self.repos[pkgroot].getManifest(product, version, flavor) man.remapEntries() # allow user to rewrite entries in the manifest if product not in [p.product for p in man.getProducts()]: raise EupsException("You asked to install %s %s but it is not in the manifest\nCheck manifest.remap (see \"eups startup\") and/or increase the verbosity" % (product, version)) self._msgs = {} self._recursiveInstall(0, man, product, version, flavor, pkgroot, productRoot, updateTags, alsoTag, options, depends, noclean, noeups)