o c*@s8ddlmZddlZddlZddlZddlZddlZddlZddlZddl m Z ddl Z ddl Z ddl Z ddlmZddlmZddlmZddlmZddlmZdd lmZmZdd lmZmZmZd d lmZGd dde Z!Gddde Z"Gddde Z#GdddeZ$GdddeZ%Gddde&Z'dS))absolute_importN) attrgetter SourcesList)AcquireProgress)InstallProgress) itervalues)StringIO)append_text_filecreate_text_file)read_text_fileread_binary_file touch_filebuild_skeleton_aptc@eZdZdZdS)TransactionErrorz)Raised when the transaction fails to run.N__name__ __module__ __qualname____doc__rrB/usr/lib/python3/dist-packages/landscape/lib/apt/package/facade.pyrrc@s eZdZdZddZddZdS)DependencyErrorz9Raised when a needed dependency wasn't explicitly marked.cCs ||_dSN)packages)selfrrrr__init__$s zDependencyError.__init__cCsdddd|jDS)NzMissing dependencies: %s, cSsg|]}t|qSr)str).0packagerrr )z+DependencyError.__str__..)joinrrrrr__str__'szDependencyError.__str__N)rrrrr r)rrrrr!s rc@r) ChannelErrorz"Raised when channels fail to load.Nrrrrrr*,rr*c@seZdZddZddZdS)LandscapeAcquireProgresscGdS)aDOverride trying to get the column count of the buffer. We always send the output to a file, not to a terminal, so the default width (80 columns) is fine for us. Overriding this method means that we don't have to care about fcntl.ioctl API differences for different Python versions. Nr)rdummyrrr_winch2szLandscapeAcquireProgress._winchcCr,)zOverride updating the acquire progress, which needs a tty. Under Python3, StringIO.fileno() raises UnsupportedOperation instead of an AttributeError. This would be uncaught by apt, thus we force a NOOP here. Tr)rownerrrrpulse<szLandscapeAcquireProgress.pulseN)rrrr.r0rrrrr+0s r+cs8eZdZdZdZfddZfddZddZZS)LandscapeInstallProgressNcstt|}t||_|S)aOverride to find out whether dpkg exited or not. The C{run()} method returns os.WEXITSTATUS(res) without checking os.WIFEXITED(res) first, so it can signal that everything is ok, even though something causes dpkg not to exit cleanly. Save whether dpkg exited cleanly into the C{dpkg_exited} attribute. If dpkg exited cleanly the exit code can be used to determine whether there were any errors. If dpkg didn't exit cleanly it should mean that something went wrong. )superr1 wait_childos WIFEXITED dpkg_exited)rres __class__rrr3Ks z#LandscapeInstallProgress.wait_childcs*tt|}|dkrtj|_|jt_|S)z6Fork and override the excepthook in the child process.r)r2r1forksys excepthookold_excepthook_prevent_dpkg_apport_error)rpidr8rrr:[s zLandscapeInstallProgress.forkcCs,|tur t|||dS||||dS)aPrevent dpkg errors from generating Apport crash reports. When dpkg reports an error, a SystemError is raised and cleaned up in C code. However, it seems like the Apport except hook is called before the C code clears the error, generating crash reports even though nothing crashed. This exception hook doesn't call the Apport hook for SystemErrors, but it calls it for all other errors. N) SystemErrorr;__excepthook__r=)rexc_typeexc_objexc_tbrrrr>es z3LandscapeInstallProgress._prevent_dpkg_apport_error) rrrr6r=r3r:r> __classcell__rrr8rr1Fs    r1c@seZdZdZdZdZdZdxddZdd Zd d Z d d Z ddZ ddZ ddZ ddZddZdyddZddZddZ  dzdd Zd!d"Zd#d$Zd%d&Zd'd(Zd)d*Zd+d,Zd-d.Zd/d0Zd{d2d3Zd4d5Zd6d7Zd8d9Zd:d;Z dd?Z"d@dAZ#dBdCZ$dDdEZ%dFdGZ&dHdIZ'dJdKZ(dLdMZ)dNdOZ*dPdQZ+dRdSZ,dTdUZ-dVdWZ.dXdYZ/dZd[Z0d\d]Z1d^d_Z2d`daZ3dbdcZ4dddeZ5dfdgZ6dhdiZ7djdkZ8dldmZ9dndoZ:dpdqZ;drdsZdS)| AptFacadeatWrapper for tasks using Apt. This object wraps Apt features, in a way that makes using and testing these features slightly more comfortable. @param root: The root dir of the Apt configuration files. @ivar refetch_package_index: Whether to refetch the package indexes when reloading the channels, or reuse the existing local database. z/var/lib/dpkg/statusNcCs||_g|_|jdur||jd|jgtjj|d|_d|_i|_ i|_ g|_ t |_ d|_g|_g|_g|_d|_dS)Nz--root)rootdirF)_root _dpkg_args_ensure_dir_structureextendaptcacheCache_cache_channels_loaded _pkg2hash _hash2pkg_version_installsset_package_installs_global_upgrade_version_removals_version_hold_creations_version_hold_removalsrefetch_package_index)rrootrrrr s   zAptFacade.__init__cCs|d}|d|d|d|d}|d|d|dttj|d d tj|d |_tj|jsGt|jd tjtj|d s]ttj|d dSdS)Nzetc/aptzetc/apt/sources.list.dzvar/cache/apt/archives/partialzvar/lib/apt/lists/partialz var/lib/dpkgzvar/lib/dpkg/infozvar/lib/dpkg/updateszvar/lib/dpkg/triggers availablestatusz trusted.gpg.dz trusted.gpg) _ensure_sub_dirr r4pathr' _dpkg_statusexistsisdirr)rapt_dirdpkg_dirrrrrLs         zAptFacade._ensure_dir_structurecCs*tj|j|}tj|st||S)z)Ensure that a dir in the Apt root exists.)r4rbr'rJrdmakedirs)rsub_dir full_pathrrrras  zAptFacade._ensure_sub_dircCs t|jS)z/Get all the packages available in the channels.)rrTr(rrr get_packages zAptFacade.get_packagescsfddDS)zqGet all packages in the channels that are locked. For Apt, it means all packages that are held. cs&g|]}|r|jr|qSr)is_package_installed_is_package_heldr$r#versionr(rrr%s z1AptFacade.get_locked_packages..rkr(rr(rget_locked_packages zAptFacade.get_locked_packagescCstdd|DS)z5Return the name of all the packages that are on hold.cSg|]}|jjqSrr$namerorrrr% z/AptFacade.get_package_holds..)sortedrrr(rrrget_package_holdsszAptFacade.get_package_holdscCs.tjddg|jtjd}||ddS)zfSet the dpkg selection. It basically does "echo $selection | dpkg --set-selections". dpkgz--set-selections)stdinutf-8N) subprocessPopenrKPIPE communicateencode)r selectionprocessrrr_set_dpkg_selectionss  zAptFacade._set_dpkg_selectionscCs||jjddS)zdAdd a dpkg hold for a package. @param version: The version of the package to hold. z holdN)rr$rvrrprrrset_package_holdszAptFacade.set_package_holdcCs0||r ||js dS||jjddS)zjRemoves a dpkg hold for a package. @param version: The version of the package to unhold. Nz install)rmrnr$rrvrrrrremove_package_holds  zAptFacade.remove_package_holdFcCs|jd|}|js|rTtj|rTi}|r |js ||d<zz |jjdi|Wnty:|jYnwWnt j j yMt d| w|jd|j|j|jD]#}||siqa|jD]}|j|dd}||j||f<||j|<qlqad|_dS)zReload the channels and update the cache. @param force_reload_binaries: Whether to always reload information about the binaries packages that are in the facade's internal repo. N sources_listz"Apt failed to reload channels (%r)F) with_infoTr)rQopen_get_internal_sources_listr\r4rbrdupdate TypeErrorrNrOFetchFailedExceptionr* get_channelsrSclearrT_is_main_architectureversionsget_package_skeletonget_hashrR)rforce_reload_binariesinternal_sources_list new_apt_argsr$rphashrrrreload_channelssP            zAptFacade.reload_channelscCs|jrdS|dS)z6Reload the channels if they haven't been reloaded yet.N)rRrr(rrrensure_channels_reloadeds z"AptFacade.ensure_channels_reloadedcCstjd}tj|dS)z@Return the path to the source.list file for the facade channels.zDir::Etc::sourcepartsz_landscape-internal-facade.list)apt_pkgconfigfind_dirr4rbr')r sources_dirrrrrs z$AptFacade._get_internal_sources_listc Cs|}d}|dur|dr|rdnd}d|}d|||}|r,|dd |7}tj|r?t|d } || vr?dS|d 7}t ||dS) a!Add a deb URL which points to a repository. @param url: The base URL of the repository. @param codename: The dist in the repository. @param components: The components to be included. @param trusted: Whether validation should be skipped (if local). r_Nzfile:yesnoz[ trusted={} ] z deb {}{} {}z %s  ) r startswithformatr'r4rbrdr splitr ) rurlcodename componentstrustedsources_file_pathsource_options trusted_val sources_linecurrent_contentrrradd_channel_apt_debs    zAptFacade.add_channel_apt_debcCs$|||jd|dddddS)zAdd a directory with packages as a channel. @param path: The path to the directory containing the packages. A Packages file is created in the directory with information about the deb files. z file://%sz./NT)r)_create_packages_filer)rrbrrradd_channel_deb_dir2s zAptFacade.add_channel_deb_dircCs&|}tj|rt|dSdS)zClear the channels that have been added through the facade. Channels that weren't added through the facade (i.e. /etc/apt/sources.list and /etc/apt/sources.list.d) won't be removed. N)rr4rbrdremove)rrrrrclear_channels?s zAptFacade.clear_channelscCstt|}ttj|ddd(}t|D]\}}|dkr$|dtj||}|||qWddS1s=wYdS)z0Create a Packages file in a directory with debs.Packageswbr N) rxr4listdirrrbr' enumeratewritewrite_package_stanza)rdeb_dirrdestifilenamedeb_filerrrrJs "zAptFacade._create_packages_filecCst}dd|DS)zReturn a list of channels configured. A channel is a deb line in sources.list or sources.list.d. It's represented by a dict with baseurl, distribution, components, and type keys. cSs.g|]}|js|j|jd|j|jdqS)r)baseurl distributionrtype)disableduridistr'compsr)r#entryrrrr%\s   z*AptFacade.get_channels..r)rrrrrrTszAptFacade.get_channelscCs&t}|D]}|dq|dS)z#Remove all the configured channels.FN)r set_enabledsave)rrrrrrreset_channels`s  zAptFacade.reset_channelscCst|}t|}|jd}|tj|}tj |}t |}t | } t | } t | } t|} d|fdt|fd| fd| fd| fg} z| |tjdd| DWd Styzt| tj| }||d Yd Sw) zWrite a stanza for the package to a Packages file. @param deb_path: The path to the deb package. @param dest: A writable package file. controlFilenameSizeMD5sumSHA1SHA256cSsg|] \}}t||qSr)r TagRewrite)r#kvrrrr%~sz2AptFacade.write_package_stanza..r|N)rapt_instDebFiler extractdatacloser4rbbasenamegetsizer hashlibmd5 hexdigestsha1sha256r TagSectionr"rREWRITE_PACKAGE_ORDERAttributeErrorrewrite_sectionr)rdeb_pathrrdebrrsizecontentsrrr tag_sectionnew_tagssectionrrrrgs4       zAptFacade.write_package_stanzacCs tjdS)z1Return the architecture APT is configured to use.APT::Architecture)rrgetr(rrrget_arch zAptFacade.get_archcCsD|durd}tjdtjd|tjd|}|jd|S)zkSet the architecture that APT should use. Setting multiple architectures isn't supported. Nr_zAPT::ArchitectureszAPT::Architectures::r)rrrrVrQr)r architectureresultrrrset_archs  zAptFacade.set_archTcCst||ddS)aReturn a skeleton for the provided package. The skeleton represents the basic structure of the package. @param pkg: Package to build skeleton from. @param with_info: If True, the skeleton will include information useful for sending data to the server. Such information isn't necessary if the skeleton will be used to build a hash. @return: a L{PackageSkeleton} object. T)r with_unicoder)rpkgrrrrrs zAptFacade.get_package_skeletoncCs|j|j|fS)ziReturn a hash from the given package. @param version: an L{apt.package.Version} object. )rSrr$rrrrget_package_hashszAptFacade.get_package_hashcCs |jS)z=Get the hashes of all the packages available in the channels.)rSvaluesr(rrrget_package_hashesrlzAptFacade.get_package_hashescCs |j|S)zGet the package having the provided hash. @param hash: The hash the package should have. @return: The L{apt.package.Package} that has the given hash. )rTr)rrrrrget_package_by_hashs zAptFacade.get_package_by_hashcCs ||jjkS)z!Is the package version installed?)r$ installedrrrrrmrzAptFacade.is_package_installedcCs|jS)z*Is the package available for installation?) downloadablerrrris_package_availableszAptFacade.is_package_availablecCs |jjr|jjs dS||jjkS)z8Is the package an upgrade for another installed package?F)r$ is_upgradablerrrrris_package_upgrades zAptFacade.is_package_upgradecCs|jjS)z;Was the package auto-installed, but isn't required anymore?)r$is_auto_removablerrrris_package_autoremovablesz"AptFacade.is_package_autoremovablecCst|dsdS|j|jkS)z2Is the package for the facade's main architecture? shortnameT)hasattrrvrrr$rrrrs  zAptFacade._is_main_architecturecCs|jjtjkS)zIs the package marked as held?)_pkgselected_stater SELSTATE_HOLDrrrrrnszAptFacade._is_package_heldcsfdd|DS)zGet all available packages matching the provided name. @param name: The name the returned packages should have. csg|] }|jjkr|qSrrurorvrrr%s  z2AptFacade.get_packages_by_name..rq)rrvrrrget_packages_by_namerszAptFacade.get_packages_by_namecCs*|jrdS|js|js|js||jvSdS)a]Is the package broken? It's considered broken if it's one that we marked for install, but it's not marked for install, upgrade or downgrade anymore. Before Trusty, checking is_inst_broken was enough, but in Trusty the behaviour changed, so the package simply gets unmarked for installation. TF)is_inst_brokenmarked_installmarked_upgrademarked_downgraderWrrrr_is_package_brokens  zAptFacade._is_package_brokencstfddDS)z/Return the packages that are in a broken state.c3s"|] }|jr|jVqdSr)r r$ror(rr s  z1AptFacade._get_broken_packages..)rVrkr(rr(r_get_broken_packagess zAptFacade._get_broken_packagescCs8|jr|jgS|js |jr|j|jgS|jr|jgSdS)a]Return the versions that will be changed for the package. Apt gives us that a package is going to be changed and have variables set on the package to indicate what will change. We need to convert that into a list of versions that will be either installed or removed, which is what the server expects to get. N)r candidaterr r marked_deleterrrr_get_changed_versionss  zAptFacade._get_changed_versionscs~dd|D}t}|jD]|sq|}|fdd|Dq||}|r9tdd|Dt|dkS)aCheck that the changes Apt will do have all been requested. @raises DependencyError: If some change hasn't been explicitly requested. @return: C{True} if all the changes that Apt will perform have been requested. cSsg|]}|j|fqSrr$rorrrr%s z,AptFacade._check_changes..c3s|]}|fVqdSrrrorrrr #s z+AptFacade._check_changes..cSsg|]\}}|qSrr)r#r$rprrrr%(r&r) rVrQ get_changesrrr differencerlen)rrequested_changes all_changesversions_to_be_changedr dependenciesrrr_check_changess"      zAptFacade._check_changescCs|jj}|jr|d|j|jf7}d}|jj|jvr:|j|jj}|js'|jr:|jj}||j vr6|jj}d|}||7}|S)zAReturn a string representation of a specific dependency relation.z (%s %s)z but is not installablez but %s is to be installed) target_pkgrv target_ver comp_typerQrrr rpr)r dep_relationinforeason dep_packagerprrr_get_unmet_relation_info+s z"AptFacade._get_unmet_relation_infocCs`|dv}|jj}|D]"}|D]}|j}|jtjks ||r+||s+|Sqq | S)a+Return whether a dependency is satisfied. For positive dependencies (Pre-Depends, Depends) it means that one of its targets is going to be installed. For negative dependencies (Conflicts, Breaks), it means that none of its targets are going to be installed. )Breaks Conflicts) rQ _depcache all_targets parent_pkg current_staterCURSTATE_INSTALLEDrr)r dependencydep_type is_positivedepcacheor_deptargetr$rrr_is_dependency_satisfied<s   z"AptFacade._is_dependency_satisfiedc s|}|sdSdg}t|tddD]^d}tfdd|jD}dD]?}|j|g}|D]3}|||r9q0g}|D] } || | q=d j |f} d d t | } || | |d }q0q%|sq|d j dfqd |S)aGet information about unmet dependencies in the cache state. Go through all the broken packages and say which dependencies haven't been satisfied. @return: A string with dependency information like what you get from apt-get. r_z/The following packages have unmet dependencies:rv)keyFc3s |] }|jkr|jVqdSr)r$_cand)r#rrrrr cs  z7AptFacade._get_unmet_dependency_info..) PreDependsDependsr"r!z %s: %s: z or rTz %s: %szUnknown dependency errorr) r rxrnextrU depends_listrr.appendr rvrr') rbroken_packagesall_infofound_dependency_errorr r)rr(relation_infosrr or_dividerrrr_get_unmet_dependency_infoQs8     z$AptFacade._get_unmet_dependency_infocCs"dtjd<dtjd<dtjd<dS)zW Set the environment to avoid attempts by apt to interact with a user. noninteractiveDEBIAN_FRONTENDnoneAPT_LISTCHANGES_FRONTENDAPT_LISTBUGS_FRONTENDN)r4environr(rrr_set_frontend_noninteractivews  z&AptFacade._set_frontend_noninteractivecCs&|tjdtjdddS)zV Setup environment and apt options for successful package operations. z DPkg::optionszDPkg::options::z--force-confoldN)rBrrrrVr(rrr_setup_dpkg_for_changess z!AptFacade._setup_dpkg_for_changescstjdkp tjdk}|sdSfddjD}|r0tdddddt|DjD]}|q3jD]}|q>d S) z> Perform pending hold operations on packages. rNcsg|] }|s|qSr)rmror(rrr%s z3AptFacade._perform_hold_changes..z0Cannot perform the changes, since the following zpackages are not installed: %sr!cSrtrrurorrrr%rwz#Package holds successfully changed.)rrZr[rr'rxrr)r hold_changes not_installedrprr(r_perform_hold_changess.      zAptFacade._perform_hold_changesc Cst}t\}}td}td}t|dt|dt}zd}||jkrd}|dkr@t |j t d|j||d7}z|j jt||d|jsVtdWnKty|} z|t|} t| jdd| }WYd} ~ n9d} ~ wtjjy} z|t|} t| jdd| }WYd} ~ nd} ~ ww|t|} n||jks*|dur|Wt|dt|dt|| St|dt|dt|w) zd Commit cached APT operations and give feedback on the results as a string. rrNzMdpkg process might be in use. Retrying package changes. %d retries remaining.)fetch_progressinstall_progresszdpkg didn't exit cleanly.z Package operation log: )r tempfilemkstempr4dupdup2r1max_dpkg_retriestimesleepdpkg_retry_sleeploggingwarningrQcommitr+r6r@getvaluer rargsrNrOLockFailedExceptionr) r fetch_outputfdinstall_output_path old_stdout old_stderrrI dpkg_trieserrorexc result_text exceptionrrr_commit_package_changess           %     z!AptFacade._commit_package_changescCst|jD]4}||jjkr q||j_|jj p|jj }|jjd|d|j|j||jj | |jj qdS)NF)auto_fix from_user) rUr$rr is_auto_installed mark_installrWaddrrprotect)rfixerrp is_manualrrr_preprocess_installss   zAptFacade._preprocess_installsc st}tdd|jDtfdd|jD}|jD]@}||jr+||jj|j|vr1q|jjdd||jj | |jj | |jj z| Wqt y\Yqw|rltdddt|dS) Ncss|]}|jVqdSrrrorrrr s z0AptFacade._preprocess_removes..c3s |] }|jvr|jVqdSrrropackage_installsrrr s F)rcz7Can't perform the changes, since the following packagesz are held: %sr!)rVrUrYrnr$rgrv mark_deleterrrhrinstall_protectrrr'rx)rriheld_package_namespackage_upgradesrprrlr_preprocess_removess8      zAptFacade._preprocess_removescCs|jr |jjdddSdS)NT) dist_upgrade)rXrQupgrader(rrr_preprocess_global_upgrade"sz$AptFacade._preprocess_global_upgradec Csv|}||kr7z|dWnty(}z t|jdd|d}~ww|}||kr9t|dSdS)zQ Attempt to automatically resolve problems with broken packages. TrrN)r resolver@rrVr;)rrialready_broken_packagesnow_broken_packagesr^rrr_resolve_broken_packages&s z"AptFacade._resolve_broken_packagescCsj|jdd}||j|s|jsgS|}t|jj}| || | || |||Sr) rUrMrYrXr rProblemResolverrQr#rkrurrry)rversion_changesrwrirrr_preprocess_package_changes6s     z%AptFacade._preprocess_package_changescCs|}||s dS|S)zD Perform pending install/remove/upgrade operations. N)r|rrb)rr{rrr_perform_package_changesCs z"AptFacade._perform_package_changescCsZ||}|}g}|dur|||dur ||t|dkr+d|SdS)z9 Perform the pending package operations. Nrr)rCrFr}r5rr')rhold_result_textpackage_result_textresultsrrrperform_changesLs    zAptFacade.perform_changescCsN|jdd=|j|jdd=|jdd=|jdd=d|_|jdS)z%Clear the pending package operations.NF)rUrWrrYr[rZrXrQr(rrr reset_marks[s     zAptFacade.reset_markscC|j|dS)z"Mark the package for installation.N)rUr5rrrrrfezAptFacade.mark_installcCs d|_dS)zUpgrade all installed packages.TN)rXr(rrrmark_global_upgradeirlzAptFacade.mark_global_upgradecCr)zMark the package for removal.N)rYr5rrrr mark_removemrzAptFacade.mark_removecCr)zMark the package to be held.N)rZr5rrrr mark_holdqrzAptFacade.mark_holdcCr)z*Mark the package to have its hold removed.N)r[r5rrrrmark_remove_holdurzAptFacade.mark_remove_holdr)F)NN)T)?rrrrrNrQrcr rLrarkrrryrrrrrrrrrrrrrrrrrrrrmrrrrrnrr r rrr r.r;rBrCrFrbrkrrruryr|r}rrrfrrrrrrrrrFvs~     ,         &E#    rF)( __future__rrrRr4r}r;rJrOoperatorrrNrraptsources.sourceslistrapt.progress.textrapt.progress.basertwisted.python.compatrlandscape.lib.compatr landscape.lib.fsr r r r rskeletonr Exceptionrrr*r+r1objectrFrrrrs4         0