U
    k&p[1]  ã                   @   sÆ   d dl mZ d dlZd dlZd dlZd dlZd dlZzd dlmZ W n  ek
rd   d dl	mZ Y nX d dl
Z
d dlZd dlZd dlZd dlZG dd„ deƒZG dd„ dejjƒZG dd	„ d	eƒZdS )
é    )Úunicode_literalsN)ÚStringIOc                   @   s    e Zd ZdZdd„ Zdd„ ZdS )ÚAppExceptionzâBase class for application specific exceptions.

    Any exceptions that are subclasses of this one get printed as
    nice errors to the user. Any other exceptions cause a Python
    stack trace to be written to stderr.

    c                 C   s   t  | ¡ || _d S ©N)Ú	ExceptionÚ__init__Úmsg©Úselfr   © r   ú,/usr/lib/python3/dist-packages/cliapp/app.pyr   .   s    
zAppException.__init__c                 C   s   | j S r   )r   ©r
   r   r   r   Ú__str__2   s    zAppException.__str__N)Ú__name__Ú
__module__Ú__qualname__Ú__doc__r   r   r   r   r   r   r   $   s   r   c                   @   s"   e Zd ZdZddd„Zdd„ ZdS )	Ú
LogHandlerz;Like RotatingFileHandler, but set permissions of new files.é€  c                 O   s"   || _ tjjj| |f|ž|Ž d S r   )Ú_permsÚloggingÚhandlersÚRotatingFileHandlerr   )r
   ÚfilenameÚpermsÚargsÚkwargsr   r   r   r   :   s    ÿÿzLogHandler.__init__c                 C   sD   t j | j¡s6t jt jB }t  | j|| j¡}t  |¡ t	j
j | ¡S r   )ÚosÚpathÚexistsZbaseFilenameÚO_CREATÚO_WRONLYÚopenr   Úcloser   r   r   Ú_open)r
   ÚflagsÚfdr   r   r   r$   ?   s
    
zLogHandler._openN)r   )r   r   r   r   r   r$   r   r   r   r   r   6   s   
r   c                   @   s¼  e Zd ZdZdfdd„Zdd„ Zdejdej	fdd	„Z
d
d„ Zdd„ Zdejej	fdd„Zdd„ Zdgdd„Zdd„ Zdd„ Zdd„ Zdd„ Zdd„ Zdd „ Zd!d"„ Zd#d$„ Zd%d&„ Zdhd'd(„Zd)d*„ Zdid+d,„Zd-d.„ Zd/d0„ Zd1d2„ Zd3d4„ Zd5d6„ Z d7d8„ Z!d9d:„ Z"d;d<„ Z#d=d>„ Z$d?d@„ Z%dAdB„ Z&dCdD„ Z'dEdF„ Z(dGdH„ Z)dIdJ„ Z*dKdL„ Z+dMdN„ Z,djdOdP„Z-dQdR„ Z.dSdT„ Z/dUdV„ Z0dWdX„ Z1dkdZd[„Z2ej3fd\d]„Z4d^d_„ Z5d`da„ Z6dbdc„ Z7ddde„ Z8dS )lÚApplicationa  A framework for Unix-like command line programs.

    The user should subclass this base class for each application.
    The subclass does not need code for the mundane, boilerplate
    parts that are the same in every utility, and can concentrate on the
    interesting part that is unique to it.

    To start the application, call the `run` method.

    The ``progname`` argument sets tne name of the program, which is
    used for various purposes, such as determining the name of the
    configuration file.

    Similarly, ``version`` sets the version number of the program.

    ``description`` and ``epilog`` are included in the output of
    ``--help``. They are formatted to fit the screen. Unlike the
    default behavior of ``optparse``, empty lines separate
    paragraphs.

    Nú0.0.0c                 C   s´   d| _ d| _d| _|| _t| dƒs(d| _t| dƒs8i | _i | _i | _t	ƒ | _
|  ¡ D ]}|  |¡}t| |ƒ| j|< qTtj||| j| j|d| _d| _t | j¡| _t ¡ d | _d S )Nr   Úarg_synopsisz	[FILE]...Úcmd_synopsis)ÚusageÚdescriptionÚepilogÚpluginséÿÿÿÿ)ÚfilenoÚglobal_linenoÚlinenoÚ_descriptionÚhasattrr)   r*   ÚsubcommandsÚsubcommand_aliasesÚsetÚhidden_subcommandsÚ_subcommand_methodnamesÚ_unnormalize_cmdÚgetattrÚcliappZSettingsÚ_format_usageÚ_format_descriptionÚsettingsÚplugin_subdirZMemoryProfileDumperÚmemory_profile_dumperr   ÚtimesZ_started)r
   ÚprognameÚversionr,   r-   Zmethod_nameÚcmdr   r   r   r   _   s,    


ýzApplication.__init__c                 C   s   dS )z"Add application specific settings.Nr   r   r   r   r   Úadd_settings}   s    zApplication.add_settingsc           	         s”   |dkrt jn|}‡ ‡‡‡fdd„}ˆjjdkrH|rHtj |d ¡ˆj_dˆ ˆjj¡ }tj 	|d¡}|rŠddl
}| dtƒ tƒ |¡ n|ƒ  dS )zRun the application.Nc                      s   ˆj ˆ ˆˆd d S )N)r   ÚstderrÚlog)Ú_runr   ©r   rH   r
   rG   r   r   Úrun_it†   s    zApplication.run.<locals>.run_itr   z
%s_PROFILEÚ zrun_it())ÚsysÚargvr?   rC   r   r   ÚbasenameÚenvnameÚenvironÚgetÚcProfileZrunctxÚglobalsÚlocals)	r
   r   rG   ZsysargvrH   rK   rP   ZprofnamerS   r   rJ   r   Úrun€   s    zApplication.runc                    sJ   t j |¡}d|kr"| d¡d }d‰ ˆ ˆ  ¡ 7 ‰ d ‡ fdd„|D ƒ¡S )z=Create an environment variable name of the name of a program.Ú.r   Z$abcdefghijklmnopqrstuvwxyz0123456789rL   c                 3   s"   | ]}|ˆ kr|  ¡ nd V  qdS )Ú_N)Úupper©Ú.0Úx©Úokr   r   Ú	<genexpr>   s     z&Application.envname.<locals>.<genexpr>)r   r   rO   ÚsplitrY   Újoin)r
   rC   rO   r   r]   r   rP   “   s    zApplication.envnamec              	   C   sR   d}t  ¡ dkrNtj |¡rNtdddƒ }| | jjd d…  	¡ ¡ W 5 Q R X d S )Nz/proc/self/commZLinuxÚwbr   é   )
ÚplatformÚsystemr   r   r   r"   Úwriter?   rC   Úencode)r
   ZcommÚfr   r   r   Ú_set_process_nameŸ   s    zApplication._set_process_namec              
   C   sŠ  zÈ|   ¡  |  ¡  |  ¡  |  ¡  |  ¡  | jr8|  ¡  |d krNtjdd … n|}| j	|dd | j
 ¡  |  	|¡}|  ¡  |  ¡  | j
d r¢t| j
d dƒ| _ntj| _|  |¡ |  ¡  |  ¡  W n¦ tjk
r } z | dt|ƒ ¡ t d¡ W 5 d }~X Y nd tjk
rN } z | dt|ƒ ¡ t d¡ W 5 d }~X Y n" tk
rš } z,|t ¡ ƒ | dt|ƒ ¡ t d¡ W 5 d }~X Y nÖ tk
r } z^|jd k	ræt|jƒt kræ|t|ƒƒ | dt|ƒ ¡ t t|jƒt kr |jnd¡ W 5 d }~X Y nX t!k
rF } zt d¡ W 5 d }~X Y n* t"k
r´ } zP|j#t#j$kr||j%d kr|t d¡ |t ¡ ƒ | dt|ƒ ¡ t d¡ W 5 d }~X Y n¼ t&k
r( } zV|t ¡ ƒ t'|dƒrþ|j%rþ| d	|j%|j(f ¡ n| d|j( ¡ t d¡ W 5 d }~X Y nH t)k
rn } z(|t ¡ ƒ | t ¡ ¡ t d¡ W 5 d }~X Y nX t* +d
| j
j,| j
j-¡ d S )Né   T)Úconfigs_onlyÚoutputÚwz
ERROR: %s
éÿ   r   zERROR: %s: %s
z%s version %s ends normally).ri   rF   Úsetup_plugin_managerÚsetupÚenable_pluginsr5   Úadd_default_subcommandsrM   rN   Ú
parse_argsr?   Zload_configsÚsetup_loggingÚ
log_configr"   rl   ÚstdoutÚprocess_argsÚcleanupÚdisable_pluginsr<   ZUnknownConfigVariablerf   ÚstrÚexitZMalformedYamlConfigr   Ú	tracebackÚ
format_excÚ
SystemExitÚcodeÚtypeÚintÚKeyboardInterruptÚIOErrorÚerrnoZEPIPEr   ÚOSErrorr4   ÚstrerrorÚBaseExceptionr   ÚinforC   rD   )r
   r   rG   rH   Úer   r   r   rI   ¥   st    



2
 þzApplication._runc                 C   s   dS )aV  Compute setting values after configs and options are parsed.

        You can override this method to implement a default value for
        a setting that is dependent on another setting. For example,
        you might have settings "url" and "protocol", where protocol
        gets set based on the schema of the url, unless explicitly
        set by the user. So if the user sets just the url, to
        "http://www.example.com/", the protocol would be set to
        "http". If the user sets both url and protocol, the protocol
        does not get modified by compute_setting_values.

        Nr   )r
   r?   r   r   r   Úcompute_setting_valuesï   s    z"Application.compute_setting_valuesFc                 C   s@   || j kr<|| j |< || j|< |p$g | j|< |r<| j |¡ dS )af  Add a subcommand.

        Normally, subcommands are defined by add ``cmd_foo`` methods
        to the application class. However, sometimes it is more convenient
        to have them elsewhere (e.g., in plugins). This method allows
        doing that.

        The callback function must accept a list of command line
        non-option arguments.

        N)r5   r*   r6   r8   Úadd)r
   ÚnameÚfuncr)   ÚaliasesZhiddenr   r   r   Úadd_subcommandý   s    


zApplication.add_subcommandc                 C   s4   d| j kr|  d| j¡ d| j kr0|  d| j¡ d S )NÚhelpzhelp-all)r5   r   r   Úhelp_allr   r   r   r   rr     s    

z#Application.add_default_subcommandsc                 O   s   t j||ŽS )a«  Return class to format subcommand documentation.

        The class will be used to format the full docstring of a
        subcommand description, but not other help texts.

        The class must have a compatible interface with
        cliapp.TextFormat.

        This method exists for those applications who want to change
        how help texts are formatted, e.g., to allow Markdown or
        reStructuredText.

        )r<   Ú
TextFormat)r
   ÚaÚkwr   r   r   Úget_subcommand_help_formatter  s    z)Application.get_subcommand_help_formatterc                 C   s   d| j j|| j| f S )Nzusage: %s %s %s)r?   rC   r*   ©r
   rE   r   r   r   Úget_subcommand_usage)  s     ÿz Application.get_subcommand_usagec           	      C   sâ   zt tj dd¡ƒ}W n tk
r.   d}Y nX |rˆ|d }|| jkrTt d| ¡‚|  |¡}| j	|d}| 
|  |¡¡}d||f }n6| j|d}tj|d}| 
| j|d¡}d||f }| jj | d	¡¡}| j |¡ d S )
NZCOLUMNSZ78éN   r   zUnknown subcommand %s)Úwidthz%s

%s)Úshow_allz%prog)r   r   rQ   rR   Ú
ValueErrorr5   r<   r   Ú_format_usage_forr•   ÚformatÚ_format_subcommand_helpr=   r’   r>   r?   rC   ra   r`   rl   rf   )	r
   r   rš   r™   rE   r+   Úfmtr,   Útextr   r   r   Ú_help_helper-  s(    



ÿzApplication._help_helperc                 C   s   |   |d¡ dS )zPrint help.FN©r¡   ©r
   r   r   r   r   r   E  s    zApplication.helpc                 C   s   |   |d¡ dS )z)Print help, including hidden subcommands.TNr¢   r£   r   r   r   r‘   I  s    zApplication.help_allc                    s   ‡ fdd„t ˆ ƒD ƒS )Nc                    s*   g | ]"}|  d ¡rt tˆ |ƒ¡r|‘qS )Úcmd_)Ú
startswithÚinspectZismethodr;   rZ   r   r   r   Ú
<listcomp>N  s   
 þz7Application._subcommand_methodnames.<locals>.<listcomp>)Údirr   r   r   r   r9   M  s    
ÿz#Application._subcommand_methodnamesc                 C   s   d|  dd¡ S )Nzcmd_%sú-rX   )Úreplacer–   r   r   r   Ú_normalize_cmdR  s    zApplication._normalize_cmdc                 C   s&   |  d¡st‚|tdƒd …  dd¡S )Nr¤   rX   r©   )r¥   ÚAssertionErrorÚlenrª   )r
   Úmethodr   r   r   r:   U  s    zApplication._unnormalize_cmdc                 C   sp   | j rhg }d}t| j ƒD ]D}ts*|| jkr| j |d¡p:d}| d|||f ¡ dt|ƒ }qd |¡S dS dS )z0Format usage, possibly also subcommands, if any.zUsage:rL   z%s %%prog [options] %s %sú Ú
N)	r5   ÚsortedÚallr8   r*   rR   Úappendr­   ra   )r
   rš   ÚlinesÚprefixrE   r   r   r   r   r=   Y  s    ÿ
zApplication._format_usagec                 C   s   | j  |d¡pd}d||f S )NrL   zUsage: %%prog [options] %s %s)r*   rR   )r
   rE   r   r   r   r   rœ   h  s    zApplication._format_usage_forc                 C   s^   | j rTg }t| j ƒD ]"}|s&|| jkr| |  |¡¡ qd |¡}d| jpLd|f S | jS dS )z9Format OptionParser description, with subcommand support.rL   z%s
%sN)r5   r±   r8   r³   Ú_format_subcommand_summaryra   r3   )r
   rš   Z	summariesrE   Zcmd_descr   r   r   r>   l  s    
zApplication._format_descriptionc                 C   s>   | j | }|jpd}| ¡ }|r.|d  ¡ }nd}d||f S )NrL   r   z* %%prog %s: %s
)r5   r   Ú
splitlinesÚstrip)r
   rE   r®   Údocr´   Zsummaryr   r   r   r¶   x  s    

z&Application._format_subcommand_summaryc                 C   sN   | j | }|jpd}| dd¡}t|ƒdkr0|S |\}}|d t |¡ S d S )NrL   r°   rj   )r5   r   r`   r­   ÚtextwrapÚdedent)r
   rE   r®   r¹   ÚtÚfirstÚrestr   r   r   rž   ‚  s    

z#Application._format_subcommand_helpc                 C   s¶   | j d }tjtjtjtjtjtjdœ}| |tj¡}| j d dkrN|  	¡ }nH| j d dkrf|  
¡ }n0| j d rˆ| j d dkrˆ|  ¡ }n|  ¡ }tj}t ¡ }| |¡ | |¡ dS )zSet up logging.z	log-level)Údebugrˆ   ZwarningÚerrorÚcriticalZfatalrH   ZsyslogrG   ZnoneN)r?   r   ÚDEBUGÚINFOZWARNINGZERRORZCRITICALZFATALrR   Ú setup_logging_handler_for_syslogÚ setup_logging_handler_for_stderrÚsetup_logging_handler_for_fileÚsetup_logging_handler_to_noneZ	getLoggerZ
addHandlerZsetLevel)r
   Z
level_nameZlevelsÚlevelÚhandlerZloggerr   r   r   rt   Œ  s(    
ú



zApplication.setup_loggingc                 C   s$   t jjdd}|  ¡ }| |¡ |S )z.Setup a logging.Handler for logging to syslog.z/dev/log)Zaddress)r   r   ZSysLogHandlerÚ"setup_logging_formatter_for_syslogÚsetFormatter©r
   rÉ   Ú	formatterr   r   r   rÄ   ©  s    
z,Application.setup_logging_handler_for_syslogc                 C   s&   d  | jj d¡¡}|d }t |¡S )z%Setup a logging.Formatter for syslog.z%%ú%z: %(levelname)s %(message)s)ra   r?   rC   r`   r   Ú	Formatter)r
   rC   rŸ   r   r   r   rÊ   ²  s    z.Application.setup_logging_formatter_for_syslogc                 C   s   t  ¡ }|  ¡ }| |¡ |S )z.Setup a logging.Handler for logging to stderr.)r   ZStreamHandlerÚ"setup_logging_formatter_for_stderrrË   rÌ   r   r   r   rÅ   ¸  s    
z,Application.setup_logging_handler_for_stderrc                 C   s   d}t  |¡S )z%Setup a logging.Formatter for stderr.z%(levelname)s %(message)s©r   rÏ   )r
   rŸ   r   r   r   rÐ   Á  s    z.Application.setup_logging_formatter_for_stderrc                 C   sF   t | jd t| jd dƒ| jd | jd dd}|  ¡ }| |¡ |S )z4Setup a logging handler for logging to a named file.rH   zlog-modeé   zlog-maxzlog-keepF)r   ZmaxBytesZbackupCountZdelay)r   r?   r   Ú setup_logging_formatter_for_filerË   rÌ   r   r   r   rÆ   Æ  s    û
z*Application.setup_logging_handler_for_filec                 C   s   d}d}t  ||¡}|S )z0Setup a logging.Formatter for logging to a file.ú%%(asctime)s %(levelname)s %(message)sú%Y-%m-%d %H:%M:%SrÑ   )r
   rŸ   ZdatefmtrÍ   r   r   r   rÓ   Ó  s    z,Application.setup_logging_formatter_for_filec                 C   s   t  d¡}|S )z<Setup a logging.Handler that does not log anything anywhere.z	/dev/null)r   ZFileHandler)r
   rÉ   r   r   r   rÇ   Ú  s    
z)Application.setup_logging_handler_to_nonec                 C   s   dS )z&Return format string for log messages.rÔ   r   r   r   r   r   Úsetup_logging_formatà  s    z Application.setup_logging_formatc                 C   s   dS )z/Return timestamp format string for log message.rÕ   r   r   r   r   r   Úsetup_logging_timestampä  s    z#Application.setup_logging_timestampc                 C   sÚ   t  d| jj| jj¡ t  dtj¡ t  dt 	¡ ¡ t  dt 
¡ ¡ t  dt ¡ ¡ t  dt ¡ ¡ t  dt ¡ ¡ t  d¡ tjD ]}t  d	|tj| ¡ q„| j ¡ }tƒ }| |¡ t  d
| ¡ ¡ t  dtj¡ d S )Nz%s version %s startszsys.argv: %rzcurrent working directory: %szuid: %szeffective uid: %szgid: %szeffective gid: %szenvironment variables:zenvironment: %s=%sz
Config:
%szPython version: %s)r   rˆ   r?   rC   rD   r¿   rM   rN   r   ÚgetcwdÚgetuidÚgeteuidÚgetgidÚgetegidrQ   Zas_cpr   rf   Úgetvalue)r
   rŒ   Úcprh   r   r   r   ru   è  s&     þ



zApplication.log_configc                 C   s(   | j j}tj| }tj |j¡p"d}|S )z½Return the directory where the application class is defined.

        Plugins are searched relative to this directory, in the subdirectory
        specified by self.plugin_subdir.

        rW   )Ú	__class__r   rM   Úmodulesr   r   ÚdirnameÚ__file__)r
   Zmodule_nameÚmodulerá   r   r   r   Úapp_directoryý  s    
zApplication.app_directoryc                 C   s,   t  ¡ | _tj |  ¡ | j¡}|g| j_dS )zCreate a plugin manager.N)	r<   ZPluginManagerÚ	pluginmgrr   r   ra   rä   r@   Z	locations)r
   rá   r   r   r   ro   
  s    
z Application.setup_plugin_managerc                 C   s*   | j jD ]}| |_| ¡  q| j  ¡  dS )zLoad plugins.N)rå   r.   Zapprp   rq   )r
   Zpluginr   r   r   rq     s    
zApplication.enable_pluginsc                 C   s   | j  ¡  d S r   )rå   ry   r   r   r   r   ry     s    zApplication.disable_pluginsc                 C   s   | j j||| j| j| jdS )zOParse the command line.

        Return list of non-option arguments.

        )rk   r)   r*   rŠ   )r?   rs   r)   r*   rŠ   )r
   r   rk   r   r   r   rs     s      ýzApplication.parse_argsc                 C   s   dS )a  Prepare for process_args.

        This method is called just before enabling plugins. By default it
        does nothing, but subclasses may override it with a suitable
        implementation. This is easier than overriding process_args
        itself.

        Nr   r   r   r   r   rp   &  s    zApplication.setupc                 C   s   dS )a  Clean up after process_args.

        This method is called just after process_args. By default it
        does nothing, but subclasses may override it with a suitable
        implementation. This is easier than overriding process_args
        itself.

        Nr   r   r   r   r   rx   0  s    zApplication.cleanupc                 C   s€   | j rr|stdƒ‚|d }|| j krV| jD ]}|| j| kr*|} qVq*td|d  ƒ‚| j | }||dd… ƒ n
|  |¡ dS )zÔProcess command line non-option arguments.

        The default is to call process_inputs with the argument list,
        or to invoke the requested subcommand, if subcommands have
        been defined.

        zmust give subcommandr   zunknown subcommand %srj   N)r5   r~   r6   Úprocess_inputs)r
   r   rE   rŒ   r®   r   r   r   rw   :  s    	


zApplication.process_argsc                 C   s   |pdgD ]}|   |¡ q
dS )a%  Process all arguments as input filenames.

        The default implementation calls process_input for each
        input filename. If no filenames were given, then
        process_input is called with ``-`` as the argument name.
        This implements the usual Unix command line practice of
        reading from stdin if no inputs are named.

        The attributes ``fileno``, ``global_lineno``, and ``lineno`` are set,
        and count files and lines. The global line number is the
        line number as if all input files were one.

        r©   N)Úprocess_input)r
   r   Úargr   r   r   ræ   U  s    zApplication.process_inputsÚrc                 C   s   |dkrt jS t||ƒS dS )a£  Open an input file for reading.

        The default behaviour is to open a file named on the local
        filesystem. A subclass might override this behavior for URLs,
        for example.

        The optional mode argument speficies the mode in which the file
        gets opened. It should allow reading. Some files should perhaps
        be opened in binary mode ('rb') instead of the default text mode.

        r©   N)rM   Ústdinr"   )r
   rŒ   Úmoder   r   r   Ú
open_inputg  s    zApplication.open_inputc                 C   sd   |  j d7  _ d| _|  |¡}|D ],}|  jd7  _|  jd7  _|  ||¡ q"||kr`| ¡  dS )zgProcess a particular input file.

        The ``stdin`` argument is meant for unit test only.

        rj   r   N)r0   r2   rì   r1   Úprocess_input_liner#   )r
   rŒ   rê   rh   Úliner   r   r   rç   y  s    
zApplication.process_inputc                 C   s   dS )zÄProcess one line of the input file.

        Applications that are line-oriented can redefine only this method in
        a subclass, and should not need to care about the other methods.

        Nr   )r
   r   rî   r   r   r   rí   Š  s    zApplication.process_input_linec                 O   s   t j||ŽS r   )r<   Úruncmd©r
   r   r   r   r   r   rï   ’  s    zApplication.runcmdc                 O   s   t j||ŽS r   )r<   Úruncmd_uncheckedrð   r   r   r   rñ   •  s    zApplication.runcmd_uncheckedc                 C   s   | j  |¡ d S r   )rA   Údump_memory_profiler	   r   r   r   rò   ˜  s    zApplication.dump_memory_profile)Nr(   NN)NNF)F)F)F)ré   )9r   r   r   r   r   rF   rM   rG   r   rÁ   rV   rP   ri   rI   rŠ   r   rr   r•   r—   r¡   r   r‘   r9   r«   r:   r=   rœ   r>   r¶   rž   rt   rÄ   rÊ   rÅ   rÐ   rÆ   rÓ   rÇ   rÖ   r×   ru   rä   ro   rq   ry   rs   rp   rx   rw   ræ   rì   rê   rç   rí   rï   rñ   rò   r   r   r   r   r'   G   sp     ÿ
ÿ
J     ÿ




		



r'   )Z
__future__r   r„   r¦   r   Zlogging.handlersr   r   ÚImportErrorÚiorM   r|   rd   rº   r<   r   r   r   r   r   Úobjectr'   r   r   r   r   Ú<module>   s"   