3 ܓi9@s>ddlZddlZddlmZGdddZGdddeZdS)N)sos_get_command_outputc@seZdZdZdZdZdZdZdZdZ dZ d ddZ e ddZ e ddZd!d d Zd dZd"ddZddZddZddZddZddZddZddZdS)#PackageManagerauEncapsulates a package manager. If you provide a query_command to the constructor it should print each package on the system in the following format:: package name|package.version You may also subclass this class and provide a _generate_pkg_list method to build the list of packages and versions. :cvar query_command: The command to use for querying packages :vartype query_command: ``str`` or ``None`` :cvar verify_command: The command to use for verifying packages :vartype verify_command: ``str`` or ``None`` :cvar verify_filter: Optional filter to use for controlling package verification :vartype verify_filter: ``str or ``None`` :cvar files_command: The command to use for getting file lists for packages :vartype files_command: ``str`` or ``None`` :cvar chroot: Perform a chroot when executing `files_command` :vartype chroot: ``bool`` :cvar remote_exec: If package manager is on a remote system (e.g. for sos collect), use this to execute commands :vartype remote_exec: ``SoSTransport.run_command()`` NcCs d|_g|_||_|r||_dS)N) _packagesfiles remote_execchroot)selfrrr /usr/lib/python3.6/__init__.py__init__8s zPackageManager.__init__cCs|jdkr|j|jS)N)r_generate_pkg_list)rr r r packages@s zPackageManager.packagescCs|jjjjddddS)Npackage)maxsplitr) __class____name__lowersplit)rr r r manager_nameFszPackageManager.manager_nameFcCsB|jr|j|||||}nt||||d}|ddkr>|dSdS)a  Runs a package manager command, either via sos_get_command_output() if local, or via a SoSTransport's run_command() if this needs to be run remotely, as in the case of remote nodes for use during `sos collect`. :param command: The command to execute :type command: ``str`` :param timeout: Timeout for command to run, in seconds :type timeout: ``int`` :param need_root: Does the command require root privileges? :type need_root: ``bool`` :param env: Environment variables to set :type env: ``dict`` with keys being env vars to define :param use_shell: If running remotely, does the command require obtaining a shell? :type use_shell: ``bool`` :param chroot: If necessary, chroot command execution to here :type chroot: ``None`` or ``str`` :returns: The output of the command :rtype: ``str`` )renvZstatusroutput)rr)rZcommandtimeoutZ need_rootrZ use_shellrretr r r exec_cmdJs zPackageManager.exec_cmdcCstj|jj|S)z Get a list of packages that match name. :param name: The name of the package :type name: ``str`` :returns: List of all packages matching `name` :rtype: ``list`` )fnmatchfilterr keys)rnamer r r all_pkgs_by_namess zPackageManager.all_pkgs_by_namercs tj||fdd|jDS)aL Get a list of packages that match regex_name. :param regex_name: The regex to use for matching package names against :type regex_name: ``str`` :param flags: Flags for the `re` module when matching `regex_name` :returns: All packages matching `regex_name` :rtype: ``list`` csg|]}j|r|qSr )match).0pkg)regr r sz9PackageManager.all_pkgs_by_name_regex..)recompiler )rZ regex_nameflagsr )r%r all_pkgs_by_name_regexs z%PackageManager.all_pkgs_by_name_regexc Cs$y |j|Stk rdSXdS)z Get a single package that matches name. :param name: The name of the package :type name: ``str`` :returns: The first package that matches `name` :rtype: ``str`` N)r Exception)rr r r r pkg_by_names  zPackageManager.pkg_by_namecCstdS)a+ Using the output of `query_command`, build the _packages dict. This should be overridden by distinct package managers and be a generator for _generate_pkg_list which will insert the packages into the _packages dict. This method should yield a tuple of name, version, release for each package parsed. If the package manager or distribution does not use a release field, set it to None. :param pkg_list: The output of the result of `query_command` :type pkg_list: ``str`` N)NotImplementedError)rpkg_listr r r _parse_pkg_listszPackageManager._parse_pkg_listcCsr|jdkri|_|jrn|j}|j|d|jd}x>|j|D]0}|d|djd|d|jd|j|d<q:WdS) amGenerates a dictionary of packages for internal use by the package manager in the format:: {'package_name': {'name': 'package_name', 'version': 'major.minor.version', 'release': 'package release' or None, 'pkg_manager': 'package manager name'}} Nr)rrrr.)r versionreleaseZ pkg_manager)r query_commandrrr/rr)rcmdr.r$r r r r s  z!PackageManager._generate_pkg_listcCs||jkr|j|SdS)zReturns the entry in self.packages for pkg if it exists :param pkg: The name of the package :type pkg: ``str`` :returns: Package name and version, if package exists :rtype: ``dict`` if found, else ``None`` N)r )rr$r r r pkg_versions  zPackageManager.pkg_versioncCs6|jr0|j r0|j}|j|d|jd}|j|_|jS)z Get a list of files known by the package manager :returns: All files known by the package manager :rtype: ``list`` )rr) files_commandrrr splitlines)rr5rr r r all_filess  zPackageManager.all_filesc CsR|js dSy.|jd|}|j|d|jd}|jp8dStk rLdSXdS)zGiven a path, return the package that owns that path. :param path: The filepath to check for package ownership :type path: ``str`` :returns: The package name or 'unknown' :rtype: ``str`` unknown )rrN)query_path_commandrrr9r+)rpathr5r$r r r pkg_by_paths  zPackageManager.pkg_by_pathcs|js dS|j}tdt||}|s(dSd}xH|D]@}x:|D]2tfdd|jDrZq<|rf|d7}|7}q str Generate a command to verify the list of packages given in ``packages`` using the native package manager's verification tool. The command to be executed is returned as a string that may be passed to a command execution routine (for e.g. ``sos_get_command_output()``. :param packages: a string, or a list of strings giving package names to be verified. :returns: a string containing an executable command that will perform verification of the given packages. :rtype: str or ``NoneType`` Nrc3s|]}|kVqdS)Nr )r#f)rr r sz6PackageManager.build_verify_command..r<)verify_commandr*rmapany verify_filter)rr Zby_regexZ verify_listZverify_packagesZ package_listr )rr build_verify_commands  z#PackageManager.build_verify_command)NN)rFNFN)r)r __module__ __qualname____doc__r4rCrFr8r>rrr propertyr rrr!r*r,r/r r6r:r@rGr r r r rs,    (   rcsNeZdZdZdfdd ZddZddZd d Zd d Zfd dZ Z S)MultiPackageManagera This class is used to leverage multiple individual package managers as a single entity on systems that support multiple concurrent package managers. Policies that use this approach will need to specify a primary package manager, and at least one fallback manager. When queries are sent to this manager, the primary child manager is checked first. If there is a valid, not None, response (e.g. a given package is installed) then that response is used. However, if the response is empty or None, the fallback managers are then queried in the order they were passed to MultiPackageManager during initialization. :param primary: The primary package manager to rely on :type primary: A subclass of `PackageManager` :param fallbacks: A list of package managers to use if the primary does not provide a response :type fallbacks: ``list`` of `PackageManager` subclasses Ncstjdt|ts*td|jt|ts.z1Must define at least one fallback package manager) superr issubclassrr+r isinstancelistprimary fallbacks _managersextend)rrRrSrrrM)r)rrr r 2s"     zMultiPackageManager.__init__cCstdS)a+ Using the output of `query_command`, build the _packages dict. This should be overridden by distinct package managers and be a generator for _generate_pkg_list which will insert the packages into the _packages dict. This method should yield a tuple of name, version, release for each package parsed. If the package manager or distribution does not use a release field, set it to None. :param pkg_list: The output of the result of `query_command` :type pkg_list: ``str`` N)r-)rr.r r r r/Rsz#MultiPackageManager._parse_pkg_listcCs,|js&x|jD]}|jj|jqW|jS)N)rrTrUr:)rrMr r r r:cs zMultiPackageManager.all_filescCsd|jdkri|_|jj|jjx>|jD]4}|j}x(|jD]}||jkr<|||j|<q.pkg_funcr )rrZr[r )rZrr _pm_wrappertszMultiPackageManager._pm_wrappercs8|dkrtj|Stj|}t|dr4|j|S|S)Nr r\r:__call__)r r\r:)rN__getattribute__hasattrr\)ritemattr)rr r r^s     z$MultiPackageManager.__getattribute__)NN) rrHrIrJr r/r:r r\r^ __classcell__r r )rr rLs  rL)r'rZ sos.utilitiesrrrLr r r r  s