o
    f!                     @   s   d dl Z d dlZd dlZd dlZd dlZd dlZd dlmZmZm	Z	m
Z
mZmZmZ d dlmZmZmZ d dlmZmZ d dlmZmZ eeZdZg dZdZd	ee d
e	e fddZ G dd deZ!dS )    N)AnyIterableListMappingOptionalSequencecast)helperssubputil)PackageManagerUninstalledPackages)
PER_ALWAYSPER_INSTANCE)zapt-getz(--option=Dpkg::Options::=--force-confoldz*--option=Dpkg::options::=--force-unsafe-ioz--assume-yesz--quiet)z/var/lib/dpkg/lock-frontendz/var/lib/dpkg/lockz/var/cache/apt/archives/lockz/var/lib/apt/lists/lock   cfgreturnc                 C   s   | sd}dg}n|  d}|  d}t|tr|g}n	t|ts$tdt|s:t| dkrA|rAt	|d rAt
tt |S g S )a9  Parse the 'apt_get_wrapper' section of cloud-config.

    apt_get_wrapper may be defined in cloud-config:
      apt_get_wrapper:
        enabled: true
        command: ["eatmydata"]

    The function takes the value of "apt_get_wrapper" and returns the list
    of arguments to prefix to the apt-get command.
    auto	eatmydataenabledcommandz,apt_wrapper command must be a string or listr   )get
isinstancestrlist	TypeErrorr   is_truelowerr
   whichr   r   )r   r   r    r   J/usr/lib/python3/dist-packages/cloudinit/distros/package_management/apt.pyget_apt_wrapper)   s   




"r!   c                
       s   e Zd ZdZdddddejdee deee  dee f fd	d
Z	e
dejdedd fddZdefddZddddZejdddd Zdee fddZdedefddZd$ddZd d! Zefd"d#Z  ZS )%Aptaptr   Napt_get_wrapper_commandapt_get_commandapt_get_upgrade_subcommandrunnerr%   r&   r'   c                   sN   t  | |d u rt| _|d u rd}t|t| j | _|| _ddi| _d S )Nzdist-upgradeDEBIAN_FRONTENDnoninteractive)super__init__APT_GET_COMMANDr&   tupleapt_commandr'   environment)selfr(   r%   r&   r'   	__class__r   r    r,   M   s   zApt.__init__r   r   c                 C   s&   t |t|d|d|ddS )Napt_get_wrapperr&   r'   r$   )r"   r!   r   )clsr(   r   r   r   r    from_configa   s   zApt.from_configc                 C   s   t t| jd S )Nr   )boolr
   r   r&   r1   r   r   r    	availablel   s   zApt.availableF)forcec                C   s$   | j jd| jdg|rtntd d S )Nzupdate-sourcesupdate)freq)r(   runrun_package_commandr   r   )r1   r:   r   r   r    update_package_sourceso   s   

zApt.update_package_sources   )maxsizec                 C   s   t  ddgj}t| S )Nz	apt-cachepkgnames)r
   stdoutset
splitlines)r1   respr   r   r    get_all_packagesw   s   zApt.get_all_packagespkglistc                    s    fdd|D S )Nc                    s.   g | ]}t d |d d  vr|qS )z/|=r   z-^)resplitrstriprG   ).0pkgr8   r   r    
<listcomp>   s    z0Apt.get_unavailable_packages.<locals>.<listcomp>r   )r1   rH   r   r8   r    get_unavailable_packages   s   
zApt.get_unavailable_packagesc                    sd   |    tdt|}| dd |D   rtd   fdd|D }|r0| jd|d  S )N%s=%sc                 S   s   g | ]	}| d d qS )=r   )rJ   )rL   xr   r   r    rN      s    z(Apt.install_packages.<locals>.<listcomp>zXThe following packages were not found by APT so APT will not attempt to install them: %sc                    s   g | ]}| vr|qS r   r   )rL   punavailabler   r    rN      s    install)pkgs)r?   r   expand_package_listr   rO   LOGdebugr>   )r1   rH   
to_installr   rT   r    install_packages   s   zApt.install_packagesc                 C   s   |d u rg }t | j}|rt|tr|| n|r$t|t r$|| |dkr+| j}|| td|}|| | j	||| j
ddd d S )NupgraderP   F)args
update_envcapture)	short_cmdsubp_kwargs)r   r/   r   r   appendextendr'   r   rX   _wait_for_apt_commandr0   )r1   r   r^   rW   full_commandrH   r   r   r    r>      s&   




zApt.run_package_commandc              
   C   s   t D ]<}tj|sqt|d&}zt|tjtjB  W n t	y.   Y W d    dS w W d   n1 s9w   Y  qdS )ztDetermines if another process holds any apt locks.

        If all locks are clear, return True else False.
        wNFT)
APT_LOCK_FILESospathexistsopenfcntllockfLOCK_EXLOCK_NBOSError)r1   lockhandler   r   r    _apt_lock_available   s   zApt._apt_lock_availablec                 C   s   t  }td t  | |k r\|  st d q	td zd| dd|d  d}tjtj|t	j	|d	W S  t	j
yS   |  rG td
 t d Y nw t  | |k std)zWait for apt install to complete.

        short_cmd: Name of command like "upgrade" or "install"
        subp_kwargs: kwargs to pass to subp
        zWaiting for APT lockr@   zAPT lock availablezapt-z [ r^   ])logfuncmsgfunckwargsz*Another process holds APT lock. Waiting...zCould not get APT lock)time	monotonicrY   rZ   rt   sleepjoinr   log_timer
   ProcessExecutionErrorTimeoutError)r1   ra   rb   timeout
start_timelog_msgr   r   r    re      s.   



zApt._wait_for_apt_command)NN)__name__
__module____qualname__namer	   Runnersr   r   r   r,   classmethodr   r6   r7   r9   r?   	functools	lru_cacherG   r   rO   r   r\   r>   rt   APT_LOCK_WAIT_TIMEOUTre   __classcell__r   r   r2   r    r"   J   s4    



	
r"   )"rm   r   loggingri   rI   r{   typingr   r   r   r   r   r   r   	cloudinitr	   r
   r   4cloudinit.distros.package_management.package_managerr   r   cloudinit.settingsr   r   	getLoggerr   rY   r-   rh   r   dictr   r!   r"   r   r   r   r    <module>   s    $
!