o
    Thc                     @   s   d dl Z d dlZd dlmZ d dlmZ d dl mZ d dlmZm	Z	m
Z
mZmZmZmZ d dlmZ ddlmZmZ dd	lmZmZmZ dd
lmZ ddlmZ erXd dlmZ G dd deZG dd deZdS )    N)contextmanager)cycle)PathLike)TYPE_CHECKINGAny	GeneratorIteratorListOptionalUnion)Mock   )Config	DataProxy)FailureAuthFailureResponseNotAccepted)Result)FailingResponder)Runnerc                	   @   s"  e Zd ZdZd!dee ddfddZedefddZej	d	eddfd
dZde
dedee fddZddde
dedee fddZde
dedee fddZddde
dedee fddZde
de
fddZede
ded fddZede
fddZedeee
f ded fdd ZdS )"Contexta  
    Context-aware API wrapper & state-passing object.

    `.Context` objects are created during command-line parsing (or, if desired,
    by hand) and used to share parser and configuration state with executed
    tasks (see :ref:`why-context`).

    Specifically, the class offers wrappers for core API calls (such as `.run`)
    which take into account CLI parser flags, configuration files, and/or
    changes made at runtime. It also acts as a proxy for its `~.Context.config`
    attribute - see that attribute's documentation for details.

    Instances of `.Context` may be shared between tasks when executing
    sub-tasks - either the same context the caller was given, or an altered
    copy thereof (or, theoretically, a brand new one).

    .. versionadded:: 1.0
    Nconfigreturnc                 C   sF   |dur|nt  }| j|d t }| j|d t }| j|d dS )z
        :param config:
            `.Config` object to use as the base configuration.

            Defaults to an anonymous/default `.Config` instance.
        N_config)command_prefixes)command_cwds)r   _setlist)selfr   r   r    r    A/var/www/html/venv/lib/python3.10/site-packages/invoke/context.py__init__.   s   zContext.__init__c                 C   s   | j S Nr   )r   r    r    r!   r   K   s   zContext.configvaluec                 C   s   | j |d d S )Nr   )r   )r   r$   r    r    r!   r   Q   s   commandkwargsc                 K   "   | j j| }| j||fi |S )a  
        Execute a local shell command, honoring config options.

        Specifically, this method instantiates a `.Runner` subclass (according
        to the ``runner`` config option; default is `.Local`) and calls its
        ``.run`` method with ``command`` and ``kwargs``.

        See `.Runner.run` for details on ``command`` and the available keyword
        arguments.

        .. versionadded:: 1.0
        )r   runnerslocal_runr   r%   r&   runnerr    r    r!   runZ   s   zContext.runr,   r   c                 K   s   |  |}|j|fi |S r#   )_prefix_commandsr-   )r   r,   r%   r&   r    r    r!   r*   m   s   
zContext._runc                 K   r'   )a  
        Execute a shell command via ``sudo`` with password auto-response.

        **Basics**

        This method is identical to `run` but adds a handful of
        convenient behaviors around invoking the ``sudo`` program. It doesn't
        do anything users could not do themselves by wrapping `run`, but the
        use case is too common to make users reinvent these wheels themselves.

        .. note::
            If you intend to respond to sudo's password prompt by hand, just
            use ``run("sudo command")`` instead! The autoresponding features in
            this method will just get in your way.

        Specifically, `sudo`:

        * Places a `.FailingResponder` into the ``watchers`` kwarg (see
          :doc:`/concepts/watchers`) which:

            * searches for the configured ``sudo`` password prompt;
            * responds with the configured sudo password (``sudo.password``
              from the :doc:`configuration </concepts/configuration>`);
            * can tell when that response causes an authentication failure
              (e.g. if the system requires a password and one was not
              configured), and raises `.AuthFailure` if so.

        * Builds a ``sudo`` command string using the supplied ``command``
          argument, prefixed by various flags (see below);
        * Executes that command via a call to `run`, returning the result.

        **Flags used**

        ``sudo`` flags used under the hood include:

        - ``-S`` to allow auto-responding of password via stdin;
        - ``-p <prompt>`` to explicitly state the prompt to use, so we can be
          sure our auto-responder knows what to look for;
        - ``-u <user>`` if ``user`` is not ``None``, to execute the command as
          a user other than ``root``;
        - When ``-u`` is present, ``-H`` is also added, to ensure the
          subprocess has the requested user's ``$HOME`` set properly.

        **Configuring behavior**

        There are a couple of ways to change how this method behaves:

        - Because it wraps `run`, it honors all `run` config parameters and
          keyword arguments, in the same way that `run` does.

            - Thus, invocations such as ``c.sudo('command', echo=True)`` are
              possible, and if a config layer (such as a config file or env
              var) specifies that e.g. ``run.warn = True``, that too will take
              effect under `sudo`.

        - `sudo` has its own set of keyword arguments (see below) and they are
          also all controllable via the configuration system, under the
          ``sudo.*`` tree.

            - Thus you could, for example, pre-set a sudo user in a config
              file; such as an ``invoke.json`` containing ``{"sudo": {"user":
              "someuser"}}``.

        :param str password: Runtime override for ``sudo.password``.
        :param str user: Runtime override for ``sudo.user``.

        .. versionadded:: 1.0
        )r   r(   r)   _sudor+   r    r    r!   sudos   s   EzContext.sudoc              
   K   s  | j jj}|d| j jj}|d| j jj}|di }d}|d ur(d|}d}	|r6dd|	 }	| 
|}d||	||}
tt|d	|d
d}|dt| j jj}|| z|j|
fd|i|W S  ty } zt|jtrt|j|d}| d }~ww )Npassworduserenv z	-H -u {} z--preserve-env='{}' ,zsudo -S -p '{}' {}{}{}z{}
zSorry, try again.
)patternresponsesentinelwatchers)resultprompt)r   r0   r;   popr1   r2   getformatjoinkeysr.   r   reescaper   r-   r9   appendr   
isinstancereasonr   r   r:   )r   r,   r%   r&   r;   r1   r2   r3   
user_flags	env_flagscmd_strwatcherr9   failureerrorr    r    r!   r/      s<   



zContext._sudoc                 C   s6   t | j}| j}|r|dd| d||g S )z
        Prefixes ``command`` with all prefixes found in ``command_prefixes``.

        ``command_prefixes`` is a list of strings which is modified by the
        `prefix` context manager.
        r   zcd {}z && )r   r   cwdinsertr>   r?   )r   r%   prefixescurrent_directoryr    r    r!   r.      s
   
zContext._prefix_commands)NNNc                 c   s2    | j | zdV  W | j   dS | j   w )a  
        Prefix all nested `run`/`sudo` commands with given command plus ``&&``.

        Most of the time, you'll want to be using this alongside a shell script
        which alters shell state, such as ones which export or alter shell
        environment variables.

        For example, one of the most common uses of this tool is with the
        ``workon`` command from `virtualenvwrapper
        <https://virtualenvwrapper.readthedocs.io/en/latest/>`_::

            with c.prefix('workon myvenv'):
                c.run('./manage.py migrate')

        In the above snippet, the actual shell command run would be this::

            $ workon myvenv && ./manage.py migrate

        This context manager is compatible with `cd`, so if your virtualenv
        doesn't ``cd`` in its ``postactivate`` script, you could do the
        following::

            with c.cd('/path/to/app'):
                with c.prefix('workon myvenv'):
                    c.run('./manage.py migrate')
                    c.run('./manage.py loaddata fixture')

        Which would result in executions like so::

            $ cd /path/to/app && workon myvenv && ./manage.py migrate
            $ cd /path/to/app && workon myvenv && ./manage.py loaddata fixture

        Finally, as alluded to above, `prefix` may be nested if desired, e.g.::

            with c.prefix('workon myenv'):
                c.run('ls')
                with c.prefix('source /some/script'):
                    c.run('touch a_file')

        The result::

            $ workon myenv && ls
            $ workon myenv && source /some/script && touch a_file

        Contrived, but hopefully illustrative.

        .. versionadded:: 1.0
        N)r   rC   r<   )r   r%   r    r    r!   prefix
  s
   2zContext.prefixc                 C   sf   | j sdS ttt| j D ]\}}|ds|dr nqdd | j |d D }ttjj| S )zs
        Return the current working directory, accounting for uses of `cd`.

        .. versionadded:: 1.0
        r4   ~/c                 S   s   g | ]}| d dqS ) z\ )replace).0pathr    r    r!   
<listcomp>V  s    zContext.cwd.<locals>.<listcomp>N)	r   reversedr   	enumerate
startswithstrosrV   r?   )r   irV   pathsr    r    r!   rL   B  s   zContext.cwdrV   c                 c   s:    t |}| j| zdV  W | j  dS | j  w )aq  
        Context manager that keeps directory state when executing commands.

        Any calls to `run`, `sudo`, within the wrapped block will implicitly
        have a string similar to ``"cd <path> && "`` prefixed in order to give
        the sense that there is actually statefulness involved.

        Because use of `cd` affects all such invocations, any code making use
        of the `cwd` property will also be affected by use of `cd`.

        Like the actual 'cd' shell builtin, `cd` may be called with relative
        paths (keep in mind that your default starting directory is your user's
        ``$HOME``) and may be nested as well.

        Below is a "normal" attempt at using the shell 'cd', which doesn't work
        since all commands are executed in individual subprocesses -- state is
        **not** kept between invocations of `run` or `sudo`::

            c.run('cd /var/www')
            c.run('ls')

        The above snippet will list the contents of the user's ``$HOME``
        instead of ``/var/www``. With `cd`, however, it will work as expected::

            with c.cd('/var/www'):
                c.run('ls')  # Turns into "cd /var/www && ls"

        Finally, a demonstration (see inline comments) of nesting::

            with c.cd('/var/www'):
                c.run('ls') # cd /var/www && ls
                with c.cd('website1'):
                    c.run('ls')  # cd /var/www/website1 && ls

        .. note::
            Space characters will be escaped automatically to make dealing with
            such directory names easier.

        .. versionadded:: 1.0
        .. versionchanged:: 1.5
            Explicitly cast the ``path`` argument (the only argument) to a
            string; this allows any object defining ``__str__`` to be handed in
            (such as the various ``Path`` objects out there), and not just
            string literals.
        N)r[   r   rC   r<   )r   rV   r    r    r!   cdY  s   /z
Context.cdr#   )__name__
__module____qualname____doc__r
   r   r"   propertyr   setterr[   r   r   r-   r*   r0   r/   r.   r   r   rP   rL   r   r   r_   r    r    r    r!   r      sD    
I
@7$r   c                       s   e Zd ZdZddee deddf fddZdedee fd	d
Z	de
de
defddZde
dededefddZde
dededefddZde
de
deddfddZ  ZS )MockContexta  
    A `.Context` whose methods' return values can be predetermined.

    Primarily useful for testing Invoke-using codebases.

    .. note::
        This class wraps its ``run``, etc methods in `unittest.mock.Mock`
        objects. This allows you to easily assert that the methods (still
        returning the values you prepare them with) were actually called.

    .. note::
        Methods not given `Results <.Result>` to yield will raise
        ``NotImplementedError`` if called (since the alternative is to call the
        real underlying method - typically undesirable when mocking.)

    .. versionadded:: 1.0
    .. versionchanged:: 1.5
        Added ``Mock`` wrapping of ``run`` and ``sudo``.
    Nr   r&   r   c           	         s   t  | | d|dd | D ]O\}}tttf}t|t	r3| D ]\}}| 
|||< q&nt||s=t|drC| 
|}nd}t|t|| d|| | |tt| |d qdS )	a  
        Create a ``Context``-like object whose methods yield `.Result` objects.

        :param config:
            A Configuration object to use. Identical in behavior to `.Context`.

        :param run:
            A data structure indicating what `.Result` objects to return from
            calls to the instantiated object's `~.Context.run` method (instead
            of actually executing the requested shell command).

            Specifically, this kwarg accepts:

            - A single `.Result` object.
            - A boolean; if True, yields a `.Result` whose ``exited`` is ``0``,
              and if False, ``1``.
            - An iterable of the above values, which will be returned on each
              subsequent call to ``.run`` (the first item on the first call,
              the second on the second call, etc).
            - A dict mapping command strings or compiled regexen to the above
              values (including an iterable), allowing specific
              call-and-response semantics instead of assuming a call order.

        :param sudo:
            Identical to ``run``, but whose values are yielded from calls to
            `~.Context.sudo`.

        :param bool repeat:
            A flag determining whether results yielded by this class' methods
            repeat or are consumed.

            For example, when a single result is indicated, it will normally
            only be returned once, causing ``NotImplementedError`` afterwards.
            But when ``repeat=True`` is given, that result is returned on
            every call, forever.

            Similarly, iterable results are normally exhausted once, but when
            this setting is enabled, they are wrapped in `itertools.cycle`.

            Default: ``True``.

        :raises:
            ``TypeError``, if the values given to ``run`` or other kwargs
            aren't of the expected types.

        .. versionchanged:: 1.5
            Added support for boolean and string result values.
        .. versionchanged:: 1.5
            Added support for regex dict keys.
        .. versionchanged:: 1.5
            Added the ``repeat`` keyword argument.
        .. versionchanged:: 2.0
            Changed ``repeat`` default value from ``False`` to ``True``.
        __repeatrepeatT__iter__z)Not sure how to yield results from a {!r}__{})wrapsN)superr"   r   r<   itemsr   boolr[   rD   dict
_normalizehasattr	TypeErrorr>   typer   getattr)	r   r   r&   methodresults
singletonskeyr$   err	__class__r    r!   r"     s"   8

zMockContext.__init__r$   c                 C   s|   t |dr
t|tr|g}g }|D ]}t|tr"t|rdndd}n	t|tr+t|}|| qt| dr:t|S t|S )Nri   r   r   )exitedrg   )	rq   rD   r[   rn   r   rC   rt   r   iter)r   r$   rv   objr    r    r!   rp     s   

zMockContext._normalizeattnamer%   c                 C   s   z@t | |}t|tr4z|| }W n" ty3   | D ]\}}t|dr.||r.|} nqtY nw t|}|js>||_|W S  t	t
ttfyO   t|w )Nmatch)rt   rD   ro   KeyErrorrm   rq   r   nextr%   AttributeError
IndexErrorStopIterationNotImplementedError)r   r   r%   r~   rx   r$   r:   r    r    r!   _yield_result	  s*   

zMockContext._yield_resultargsc                 O      |  d|S )N__runr   r   r%   r   r&   r    r    r!   r-   '     zMockContext.runc                 O   r   )N__sudor   r   r    r    r!   r0   .  r   zMockContext.sudor:   c                 C   sT   d |}td}zt| |}W n	 ty   |w t|ts!|| |||< dS )a  
        Modify the stored mock results for given ``attname`` (e.g. ``run``).

        This is similar to how one instantiates `MockContext` with a ``run`` or
        ``sudo`` dict kwarg. For example, this::

            mc = MockContext(run={'mycommand': Result("mystdout")})
            assert mc.run('mycommand').stdout == "mystdout"

        is functionally equivalent to this::

            mc = MockContext()
            mc.set_result_for('run', 'mycommand', Result("mystdout"))
            assert mc.run('mycommand').stdout == "mystdout"

        `set_result_for` is mostly useful for modifying an already-instantiated
        `MockContext`, such as one created by test setup or helper methods.

        .. versionadded:: 1.0
        rj   z>Can't update results for non-dict or nonexistent mock results!N)r>   rr   rt   r   rD   ro   rp   )r   r   r%   r:   heckr$   r    r    r!   set_result_for5  s   

zMockContext.set_result_forr#   )r`   ra   rb   rc   r
   r   r   r"   r   rp   r[   r   r   r-   r0   r   __classcell__r    r    rz   r!   rf     s      Prf   ) r\   rA   
contextlibr   	itertoolsr   r   typingr   r   r   r   r	   r
   r   unittest.mockr   r   r   r   
exceptionsr   r   r   r(   r   r9   r   invoke.runnersr   r   rf   r    r    r    r!   <module>   s"    $	  x