Res@sBdZddlmZddlZddlZddlZddlZddlZddlZddl Z ddl Z ddl Z ddl m Z mZddlmZddlmZmZddlmZmZmZmZdd lmZmZmZmZmZmZm Z d d d d dgZ!ej"e#Z$dZ%dZ&deddde%dfZ'dZ(Gddde)Z*Gddde)Z+Gdd d e)Z,Gdd d e,Z-Gdd d e-Z.Gdd d e-Z/e.Z0e/Z1Gddde)Z2d d!d"Z3d#d$Z4d%d&Z5d'd(Z6dS))zPEP 376 implementation.)unicode_literalsN)DistlibException resources)StringIO) get_schemeUnsupportedVersionError)MetadataMETADATA_FILENAMEWHEEL_METADATA_FILENAMELEGACY_METADATA_FILENAME)parse_requirementcached_propertyparse_name_and_version read_exports write_exports CSVReader CSVWriter DistributionBaseInstalledDistributionInstalledDistributionEggInfoDistributionDistributionPathzpydist-exports.jsonzpydist-commands.json INSTALLERRECORD REQUESTED RESOURCESSHAREDz .dist-infoc@s:eZdZdZddZddZddZdS) _CachezL A simple cache mapping names and .dist-info paths to distributions cCsi|_i|_d|_dS)zZ Initialise an instance. There is normally one for each DistributionPath. FN)namepath generated)selfr#/builddir/build/BUILDROOT/alt-python35-pip-20.2.4-5.el8.x86_64/opt/alt/python35/lib/python3.5/site-packages/pip/_vendor/distlib/database.py__init__1s  z_Cache.__init__cCs'|jj|jjd|_dS)zC Clear the cache, setting it to its initial state. FN)rclearr r!)r"r#r#r$r&9s  z _Cache.clearcCsE|j|jkrA||j|j<|jj|jgj|dS)z` Add a distribution to the cache. :param dist: The distribution to add. N)r r setdefaultkeyappend)r"distr#r#r$addAsz _Cache.addN)__name__ __module__ __qualname____doc__r%r&r+r#r#r#r$r-s   rc@seZdZdZddddZddZdd ZeeeZd d Z d d Z ddZ e ddZ ddZddZdddZddZdddZdS)rzU Represents a set of distributions installed on a path (typically sys.path). NFcCsd|dkrtj}||_d|_||_t|_t|_d|_td|_ dS)a Create an instance from a path, optionally including legacy (distutils/ setuptools/distribute) distributions. :param path: The path to use, as a list of directories. If not specified, sys.path is used. :param include_egg: If True, this instance will look for and return legacy distributions as well as those based on PEP 376. NTdefault) sysr _include_dist _include_eggr_cache _cache_egg_cache_enabledr_scheme)r"r Z include_eggr#r#r$r%Os        zDistributionPath.__init__cCs|jS)N)r6)r"r#r#r$_get_cache_enabledcsz#DistributionPath._get_cache_enabledcCs ||_dS)N)r6)r"valuer#r#r$_set_cache_enabledfsz#DistributionPath._set_cache_enabledcCs|jj|jjdS)z, Clears the internal cache. N)r4r&r5)r"r#r#r$ clear_cacheks zDistributionPath.clear_cachec cst}x|jD]}tj|}|dkr7q|jd}| s|j rZqt|j}xY|D]Q}|j|}| sp|j|krqp|jru|jt rut t t g}x9|D].}t j||} |j| } | rPqWqptj| j} td| dd} WdQRXtjd|j|j|jt|jd| d|Vqp|jrp|jd rptjd|j|j|jt|j|VqpWqWdS) zD Yield .dist-info and/or .egg(-info) distributions. NfileobjschemelegacyzFound %smetadataenv .egg-info.egg)rBrC)setr rfinder_for_pathfind is_containersortedr2endswith DISTINFO_EXTr r r posixpathjoin contextlibclosing as_streamr loggerdebugr+new_dist_classr3old_dist_class) r"seenr finderrZrsetentryZpossible_filenamesZmetadata_filenameZ metadata_pathZpydiststreamr@r#r#r$_yield_distributionsssD       z%DistributionPath._yield_distributionscCs|jj }|jo |jj }|s/|rxF|jD]8}t|trd|jj|q<|jj|q<W|rd|j_|rd|j_dS)zk Scan the path for distributions and populate the cache with those that are found. TN)r4r!r3r5rY isinstancerr+)r"Zgen_distZgen_eggr*r#r#r$_generate_caches   z DistributionPath._generate_cachecCs)|jdd}dj||gtS)ao The *name* and *version* parameters are converted into their filename-escaped form, i.e. any ``'-'`` characters are replaced with ``'_'`` other than the one in ``'dist-info'`` and the one separating the name from the version number. :parameter name: is converted to a standard distribution name by replacing any runs of non- alphanumeric characters with a single ``'-'``. :type name: string :parameter version: is converted to a standard version string. Spaces become dots, and all other non-alphanumeric characters (except dots) become dashes, with runs of multiple dashes condensed to a single dash. :type version: string :returns: directory name :rtype: string-_)replacerLrJ)clsrversionr#r#r$distinfo_dirnamesz!DistributionPath.distinfo_dirnameccs|js(xs|jD] }|VqWnW|jx|jjjD] }|VqEW|jrx|jjjD] }|VqpWdS)a5 Provides an iterator that looks for distributions and returns :class:`InstalledDistribution` or :class:`EggInfoDistribution` instances for each one of them. :rtype: iterator of :class:`InstalledDistribution` and :class:`EggInfoDistribution` instances N)r6rYr[r4r valuesr3r5)r"r*r#r#r$get_distributionss     z"DistributionPath.get_distributionscCsd}|j}|jsKx|jD]}|j|kr(|}Pq(Wnb|j||jjkr~|jj|d}n/|jr||jjkr|jj|d}|S)a= Looks for a named distribution on the path. This function only returns the first result found, as no more than one value is expected. If nothing is found, ``None`` is returned. :rtype: :class:`InstalledDistribution`, :class:`EggInfoDistribution` or ``None`` Nr) lowerr6rYr(r[r4rr3r5)r"rresultr*r#r#r$get_distributions    z!DistributionPath.get_distributionc csd}|dk r]y |jjd||f}Wn(tk r\td||fYnXx|jD]}t|dstjd|qj|j}xb|D]Z}t |\}}|dkr||kr|VPq||kr|j |r|VPqWqjWdS)a Iterates over all distributions to find which distributions provide *name*. If a *version* is provided, it will be used to filter the results. This function only returns the first result found, since no more than one values are expected. If the directory is not found, returns ``None``. :parameter version: a version specifier that indicates the version required, conforming to the format in ``PEP-345`` :type name: string :type version: string Nz%s (%s)zinvalid name or version: %r, %rprovideszNo "provides": %s) r7matcher ValueErrorrrchasattrrPrQrgrmatch) r"rr`rhr*providedpp_namep_verr#r#r$provides_distributions(       z&DistributionPath.provides_distributioncCs8|j|}|dkr+td||j|S)z5 Return the path to a resource file. Nzno distribution named %r found)rf LookupErrorget_resource_path)r"r relative_pathr*r#r#r$ get_file_path!s zDistributionPath.get_file_pathccszxs|jD]e}|j}||kr ||}|dk rV||krr||Vq x|jD] }|VqcWq WdS)z Return all of the exported entries in a particular category. :param category: The category to search for entries. :param name: If specified, only entries with that name are returned. N)rcexportsrb)r"categoryrr*rVdvr#r#r$get_exported_entries*s      z%DistributionPath.get_exported_entries)r,r-r.r/r%r8r:propertyZ cache_enabledr;rYr[ classmethodrarcrfrprtryr#r#r#r$rKs     ,   ) c@seZdZdZdZdZddZeddZeZ eddZ ed d Z d d Z ed dZ eddZeddZeddZeddZddZddZddZddZdS) rz A base class for distributions, whether installed or from indexes. Either way, it must have some metadata, so that's all that's needed for construction. FcCsp||_|j|_|jj|_|j|_d|_d|_d|_d|_t |_ i|_ dS)z Initialise an instance. :param metadata: The instance of :class:`Metadata` describing this distribution. N) r@rrdr(r`locatordigestextrascontextrDZ download_urlsdigests)r"r@r#r#r$r%Os        zDistribution.__init__cCs |jjS)zH The source archive download URL for this distribution. )r@ source_url)r"r#r#r$r`szDistribution.source_urlcCsd|j|jfS)zX A utility property which displays the name and version in parentheses. z%s (%s))rr`)r"r#r#r$name_and_versioniszDistribution.name_and_versioncCs?|jj}d|j|jf}||kr;|j||S)z A set of distribution names and versions provided by this distribution. :return: A set of "name (version)" strings. z%s (%s))r@rgrr`r))r"plistsr#r#r$rgps    zDistribution.providescCsS|j}tjd|jt||}t|j|d|jd|jS)Nz%Getting requirements from metadata %rr~rA) r@rPrQZtodictgetattrrDget_requirementsr~r)r"Zreq_attrmdZreqtsr#r#r$_get_requirements|s  zDistribution._get_requirementscCs |jdS)N run_requires)r)r"r#r#r$rszDistribution.run_requirescCs |jdS)N meta_requires)r)r"r#r#r$rszDistribution.meta_requirescCs |jdS)Nbuild_requires)r)r"r#r#r$rszDistribution.build_requirescCs |jdS)N test_requires)r)r"r#r#r$rszDistribution.test_requirescCs |jdS)N dev_requires)r)r"r#r#r$rszDistribution.dev_requiresc Cst|}t|jj}y|j|j}WnAtk rwtjd||j d}|j|}YnX|j }d}x[|j D]P}t |\}} ||krqy|j | }PWqtk rYqXqW|S)z Say if this instance matches (fulfills) a requirement. :param req: The requirement to match. :rtype req: str :return: True if it matches, else False. z+could not read version %r - using name onlyrF)r rr@r>rh requirementrrPwarningsplitr(rgrrk) r"reqrVr>rhrrermrnror#r#r$matches_requirements*       z Distribution.matches_requirementcCs6|jrd|j}nd}d|j|j|fS)zC Return a textual representation of this instance, z [%s]r<z)rrr`)r"suffixr#r#r$__repr__s zDistribution.__repr__cCs[t|t|k r!d}n6|j|jkoT|j|jkoT|j|jk}|S)a< See if this distribution is the same as another. :param other: The distribution to compare with. To be equal to one another. distributions must have the same type, name, version and source_url. :return: True if it is the same, else False. F)typerr`r)r"otherrer#r#r$__eq__s  zDistribution.__eq__cCs't|jt|jt|jS)zH Compute hash in a way which matches the equality test. )hashrr`r)r"r#r#r$__hash__szDistribution.__hash__N)r,r-r.r/Zbuild_time_dependency requestedr%rzr download_urlrrgrrrrrrrrrrr#r#r#r$r=s$    " cs@eZdZdZdZdfddZdddZS)rz] This is the base class for installed distributions (whether PEP 376 or legacy). Ncs,tt|j|||_||_dS)a Initialise an instance. :param metadata: An instance of :class:`Metadata` which describes the distribution. This will normally have been initialised from a metadata file in the ``path``. :param path: The path of the ``.dist-info`` or ``.egg-info`` directory for the distribution. :param env: This is normally the :class:`DistributionPath` instance where this distribution was found. N)superrr%r dist_path)r"r@r rA) __class__r#r$r%s  z"BaseInstalledDistribution.__init__cCs|dkr|j}|dkr3tj}d}ntt|}d|j}||j}tj|jdjd}d||fS)a Get the hash of some data, using a particular hash algorithm, if specified. :param data: The data to be hashed. :type data: bytes :param hasher: The name of a hash implementation, supported by hashlib, or ``None``. Examples of valid values are ``'sha1'``, ``'sha224'``, ``'sha384'``, '``sha256'``, ``'md5'`` and ``'sha512'``. If no hasher is specified, the ``hasher`` attribute of the :class:`InstalledDistribution` instance is used. If the hasher is determined to be ``None``, MD5 is used as the hashing algorithm. :returns: The hash of the data. If a hasher was explicitly specified, the returned hash will be prefixed with the specified hasher followed by '='. :rtype: str Nr<z%s==asciiz%s%s) hasherhashlibmd5rr}base64urlsafe_b64encoderstripdecode)r"datarprefixr}r#r#r$get_hashs      !z"BaseInstalledDistribution.get_hash)r,r-r.r/rr%rr#r#)rr$rs cseZdZdZdZddfddZddZdd Zd d Ze d d Z ddZ ddZ ddZ ddZdddZddZe ddZdddZdd Zd!d"Zd#d$Zd%d&ZejZS)'ra  Created with the *path* of the ``.dist-info`` directory provided to the constructor. It reads the metadata contained in ``pydist.json`` when it is instantiated., or uses a passed in Metadata instance (useful for when dry-run mode is being used). sha256Nc sg|_tj||_}|dkr;td||rr|jrr||jjkrr|jj|j}n|dkr|j t }|dkr|j t }|dkr|j t }|dkrtdt |ft j|j}td|dd}WdQRXtt|j||||rT|jrT|jj||j d}|dk |_tjj|d}tjj|rt|d}|jjd } WdQRX| j|_dS) Nzfinder unavailable for %szno %s found in %sr=r>r?rz top_level.txtrbzutf-8)modulesrrErUrir6r4r r@rFr r r rMrNrOr rrr%r+rosrLexistsopenreadr splitlines) r"r r@rArUrVrXrmfr)rr#r$r%s6  !      zInstalledDistribution.__init__cCsd|j|j|jfS)Nz#)rr`r )r"r#r#r$r=szInstalledDistribution.__repr__cCsd|j|jfS)Nz%s %s)rr`)r"r#r#r$__str__AszInstalledDistribution.__str__c Csg}|jd}tj|j|}td|c}xY|D]Q}ddtt|dD}||\}}} |j||| fqFWWdQRXWdQRX|S)a" Get the list of installed files for the distribution :return: A list of tuples of path, hash and size. Note that hash and size might be ``None`` for some entries. The path is exactly as stored in the file (which is as in PEP 376). rrXcSsg|] }dqS)Nr#).0ir#r#r$ Ss z6InstalledDistribution._get_records..N)get_distinfo_resourcerMrNrOrrangelenr)) r"resultsrVrXZ record_readerrowmissingr checksumsizer#r#r$ _get_recordsDs "(z"InstalledDistribution._get_recordscCs+i}|jt}|r'|j}|S)a Return the information exported by this distribution. :return: A dictionary of exports, mapping an export category to a dict of :class:`ExportEntry` instances describing the individual export entries, and keyed by name. )rEXPORTS_FILENAMEr)r"rerVr#r#r$ru[s  zInstalledDistribution.exportsc CsJi}|jt}|rFtj|j}t|}WdQRX|S)z Read exports data from a file in .ini format. :return: A dictionary of exports, mapping an export category to a list of :class:`ExportEntry` instances describing the individual export entries. N)rrrMrNrOr)r"rerVrXr#r#r$ris z"InstalledDistribution.read_exportsc Cs9|jt}t|d}t||WdQRXdS)a Write a dictionary of exports to a file in .ini format. :param exports: A dictionary of exports, mapping an export category to a list of :class:`ExportEntry` instances describing the individual export entries. wN)get_distinfo_filerrr)r"rurfrr#r#r$rxsz#InstalledDistribution.write_exportscCs|jd}tj|jG}td|.}x$|D]\}}||kr@|Sq@WWdQRXWdQRXtd|dS)aW NOTE: This API may change in the future. Return the absolute path to a resource file with the given relative path. :param relative_path: The path, relative to .dist-info, of the resource of interest. :return: The absolute path where the resource is to be found. rrXNz3no resource file with relative path %r is installed)rrMrNrOrKeyError)r"rsrVrXZresources_readerZrelativeZ destinationr#r#r$rrs  z'InstalledDistribution.get_resource_pathccs x|jD] }|Vq WdS)z Iterates over the ``RECORD`` entries and returns a tuple ``(path, hash, size)`` for each line. :returns: iterator of (path, hash, size) N)r)r"rer#r#r$list_installed_filessz*InstalledDistribution.list_installed_filesFc Cstjj|d}tjj|j}|j|}tjj|d}|jd}tjd||rwdSt|}x|D]}tjj |s|j d rd} } nDdtjj |} t |d} |j | j} WdQRX|j|s)|r>|j|r>tjj||}|j|| | fqW|j|r|tjj||}|j|ddfWdQRX|S) z Writes the ``RECORD`` file, using the ``paths`` iterable passed in. Any existing ``RECORD`` file is silently overwritten. prefix is used to determine when to write absolute paths. r<rz creating %sN.pyc.pyoz%dr)rr)rr rLdirname startswithrrPinforisdirrIgetsizerrrrelpathwriterow) r"pathsrdry_runbaseZbase_under_prefix record_pathwriterr hash_valuerfpr#r#r$write_installed_filess. ! z+InstalledDistribution.write_installed_filesc Csg}tjj|j}|jd}x`|jD]R\}}}tjj|smtjj||}||kr|q7tjj|s|j|dddfq7tjj |r7t tjj |}|r||kr|j|d||fq7|r7d|kr-|j ddd}nd }t |d D} |j| j|} | |kr|j|d || fWd QRXq7W|S) a Checks that the hashes and sizes of the files in ``RECORD`` are matched by the files themselves. Returns a (possibly empty) list of mismatches. Each entry in the mismatch list will be a tuple consisting of the path, 'exists', 'size' or 'hash' according to what didn't match (existence is checked first, then size, then hash), the expected value and the actual value. rrTFr=rrNrr)rr rrrisabsrLrr)isfilestrrrrrr) r" mismatchesrrr rrZ actual_sizerrZ actual_hashr#r#r$check_installed_filess.    $z+InstalledDistribution.check_installed_filesc Csi}tjj|jd}tjj|rtj|ddd}|jj}WdQRXxX|D]P}|jdd\}}|dkr|j |gj |qk|||.set_name_and_version) r rr6r5r@rr` _get_metadatar+rrr%)r"r rArr@)rr#r$r%bs   !zEggInfoDistribution.__init__csd}ddfdd}d}}|jdrgtjj|rtjj|d}tjj|d}td|d d }tjj|d } tjj|d }|| }qtj|} t| j d j d} td| d d }y@| j d} | j dj d}| j d}Wqt k rcd}YqXn|jdrtjj|rtjj|d } || }tjj|d}tjj|d }td|d d }nt d||r|j ||dkrf|dk rftjj|rft|d} | jj d}WdQRX|sug}n |j}||_|S)NcSsg}|j}x|D]}|j}|jdrKtjd|Pt|}|sptjd|q|jrtjd|js|j|j qdj dd|jD}|jd|j |fqW|S) zCreate a list of dependencies from a requires.txt file. *data*: the contents of a setuptools-produced requires.txt file. [z.Unexpected line: quitting requirement scan: %rz#Not recognised as a requirement: %rz4extra requirements in requires.txt are not supportedz, css|]}d|VqdS)z%s%sNr#)rcr#r#r$ szQEggInfoDistribution._get_metadata..parse_requires_data..z%s (%s)) rstriprrPrr r~ constraintsr)rrL)rreqsrrrVZconsr#r#r$parse_requires_datazs&        z>EggInfoDistribution._get_metadata..parse_requires_datacsTg}y5tj|dd}|j}WdQRXWntk rOYnX|S)zCreate a list of dependencies from a requires.txt file. *req_path*: the path to a setuptools-produced requires.txt file. rVzutf-8N)rrrIOError)req_pathrr)rr#r$parse_requires_paths z>EggInfoDistribution._get_metadata..parse_requires_pathz.eggzEGG-INFOzPKG-INFOr r>r?z requires.txtz top_level.txtzEGG-INFO/PKG-INFOutf8r=zEGG-INFO/requires.txtzEGG-INFO/top_level.txtzutf-8z .egg-infoz,path must end with .egg-info or .egg, got %rr)rIrr rrLr zipimport zipimporterrget_datarrrZadd_requirementsrrrrr)r"r requiresrZtl_pathZtl_datarm meta_pathr@rZzipfr=rrr#)rr$rwsT          z!EggInfoDistribution._get_metadatacCsd|j|j|jfS)Nz!)rr`r )r"r#r#r$rszEggInfoDistribution.__repr__cCsd|j|jfS)Nz%s %s)rr`)r"r#r#r$rszEggInfoDistribution.__str__cCsg}tjj|jd}tjj|rxW|jD]I\}}}||kr[q=tjj|s=|j|dddfq=W|S)a Checks that the hashes and sizes of the files in ``RECORD`` are matched by the files themselves. Returns a (possibly empty) list of mismatches. Each entry in the mismatch list will be a tuple consisting of the path, 'exists', 'size' or 'hash' according to what didn't match (existence is checked first, then size, then hash), the expected value and the actual value. zinstalled-files.txtrTF)rr rLrrr))r"rrr r]r#r#r$rs  z)EggInfoDistribution.check_installed_filesc Cs-dd}dd}tjj|jd}g}tjj|r)tj|ddd}x|D]}|j}tjjtjj|j|}tjj|stj d ||j d rqjtjj |sj|j |||||fqjWWd QRX|j |d d f|S)z Iterates over the ``installed-files.txt`` entries and returns a tuple ``(path, hash, size)`` for each line. :returns: a list of (path, hash, size) c Ss@t|d}z|j}Wd|jXtj|jS)Nr)rrcloserr hexdigest)r rcontentr#r#r$_md5s  z6EggInfoDistribution.list_installed_files.._md5cSstj|jS)N)rstatst_size)r r#r#r$_sizesz7EggInfoDistribution.list_installed_files.._sizezinstalled-files.txtrVrzutf-8zNon-existent file: %s.pyc.pyoN)rr) rr rLrrrrnormpathrPrrIrr))r"r rrrerrrmr#r#r$rs"    $-z(EggInfoDistribution.list_installed_filesFc cstjj|jd}tjj|rd}tj|ddd}x~|D]v}|j}|dkryd}qR|sRtjjtjj|j|}|j|jrR|r|VqR|VqRWWdQRXdS) a  Iterates over the ``installed-files.txt`` entries and returns paths for each line if the path is pointing to a file located in the ``.egg-info`` directory or one of its subdirectories. :parameter absolute: If *absolute* is ``True``, each returned path is transformed into a local absolute path. Otherwise the raw value from ``installed-files.txt`` is returned. :type absolute: boolean :returns: iterator of paths zinstalled-files.txtTrVrzutf-8z./FN) rr rLrrrrrr)r"Zabsoluterskiprrrmr#r#r$rs    $z'EggInfoDistribution.list_distinfo_filescCst|to|j|jkS)N)rZrr )r"rr#r#r$r.szEggInfoDistribution.__eq__)r,r-r.r/rrr%rrrrrrrrrr#r#)rr$rYs  Z    & c@seZdZdZddZddZdddZd d Zd d Zd ddZ dddZ ddZ ddZ dS)DependencyGrapha Represents a dependency graph between distributions. The dependency relationships are stored in an ``adjacency_list`` that maps distributions to a list of ``(other, label)`` tuples where ``other`` is a distribution and the edge is labeled with ``label`` (i.e. the version specifier, if such was provided). Also, for more efficient traversal, for every distribution ``x``, a list of predecessors is kept in ``reverse_list[x]``. An edge from distribution ``a`` to distribution ``b`` means that ``a`` depends on ``b``. If any missing dependencies are found, they are stored in ``missing``, which is a dictionary that maps distributions to a list of requirements that were not provided by any other distributions. cCsi|_i|_i|_dS)N)adjacency_list reverse_listr)r"r#r#r$r%Is  zDependencyGraph.__init__cCsg|j| "%s" [label="%s"] z "%s" -> "%s" zsubgraph disconnected { zlabel = "Disconnected" zbgcolor = red z"%s"rz} )rritemsrr)r)r"rZskip_disconnectedZ disconnectedr*adjsrrr#r#r$to_dots&     %     zDependencyGraph.to_dotcsg}i}x1|jjD] \}}|dd||.zMoving to result: %scSs&g|]}d|j|jfqS)z%s (%s))rr`)rrwr#r#r$rs )rr#listr)rPrQrkeys)r"realistkrxr#)r&r$topological_sorts$)  ! z DependencyGraph.topological_sortcCsIg}x3|jjD]"\}}|j|j|qWdj|S)zRepresentation of the graphr)rr#r)rrL)r"r!r*r$r#r#r$rszDependencyGraph.__repr__) r,r-r.r/r%rrrrrr%r+rr#r#r#r$r9s      rr0cCst|}t}i}xv|D]n}|j|xX|jD]M}t|\}}tjd||||j|gj||fq?Wq"Wx.|D]&}|j |j B|j B|j B}x|D]} y|j | } WnAtk r"tjd| | jd}|j |} YnX| j}d} ||krxf||D]Z\}} y| j|} Wntk rd} YnX| rI|j|| | d} PqIW| s|j|| qWqW|S)a6Makes a dependency graph from the given distributions. :parameter dists: a list of distributions :type dists: list of :class:`distutils2.database.InstalledDistribution` and :class:`distutils2.database.EggInfoDistribution` instances :rtype: a :class:`DependencyGraph` instance zAdd to provided: %s, %s, %sz+could not read version %r - using name onlyrFT)rrrrgrrPrQr'r)rrrrrhrrrr(rkrr)distsr>graphrlr*rmrr`rrrhmatchedZproviderrkr#r#r$ make_graphsD    '        r/cCs||krtd|jt|}|g}|j|}xT|r|j}|j|x.|j|D]}||krq|j|qqWqDW|jd|S)zRecursively generate a list of distributions from *dists* that are dependent on *dist*. :param dists: a list of distributions :param dist: a distribution, member of *dists* for which we are interested z1given distribution %r is not a member of the listr)rrr/rpopr))r,r*r-deptodorwsuccr#r#r$get_dependent_distss          r4cCs||krtd|jt|}g}|j|}xX|r|jd}|j|x.|j|D]}||krr|j|qrWqAW|S)zRecursively generate a list of distributions from *dists* that are required by *dist*. :param dists: a list of distributions :param dist: a distribution, member of *dists* for which we are interested z1given distribution %r is not a member of the listr)rrr/rr0r))r,r*r-rr2rwpredr#r#r$get_required_distss       r6cKsI|jdd}t|}||_||_|p9d|_t|S)zO A convenience method for making a dist given just a name and version. summaryzPlaceholder for summary)r0r rr`r7r)rr`kwargsr7rr#r#r$ make_dist2s    r9)7r/ __future__rrrrMrloggingrrKr1rr<rrcompatrr`rrr@r r r r utilr rrrrrr__all__ getLoggerr,rPrZCOMMANDS_FILENAMErrJrrrrrrrrRrSrr/r4r6r9r#r#r#r$sL         "4  7I6