
    Kp                        S r SSKJr  SSKJr  SSKJr  SSKrSSKrSSKrSSKrSSK	r	SSK
r
SSKJr  SSKrSrSrS	r " S
 S\5      r " S S\R&                  " \R(                  \5      5      r " S S\R&                  " \R(                  \5      5      r " S S\5      r " S S\5      r " S S\5      rS r " S S\5      rg)a  The local coshell module.

A coshell is an interactive non-login /bin/bash running as a coprocess. It has
the same stdin, stdout and stderr as the caller and reads command lines from a
pipe. Only one command runs at a time. ctrl-c interrupts and kills the currently
running command but does not kill the coshell. The coshell process exits when
the shell 'exit' command is executed. State is maintained by the coshell across
commands, including the current working directory and local and environment
variables. ~/.bashrc, if it exists, is sourced into the coshell at startup.
This gives the caller the opportunity to set up aliases and default
'set -o ...' shell modes.

Usage:
  cosh = coshell.Coshell()
  while True:
    command = <the next command line to run>
    try:
      command_exit_status = cosh.Run(command)
    except coshell.CoshellExitError:
      break
  coshell_exit_status = cosh.Close()

This module contains three Coshell implementations:
  * _UnixCoshell using /bin/bash
  * _MinGWCoshell using MinGW bash or git bash
  * _WindowsCoshell using cmd.exe, does not support state across commands
On the first instantiation Coshell.__init__() determines what implementation to
use. All subsequent instantiations will use the same implementation.
    )absolute_import)division)unicode_literalsN)encodingCOSHELLz1.1a  
# Defines functions to support completion requests to the coshell.
#
# The only coshell specific shell globals are functions prefixed by __coshell_.
# All other globals are part of the bash completion api.

__coshell_get_completions__() {
  # Prints the completions for the (partial) command line "$@" terminated by
  # a blank line sentinel. The first arg is either 'prefix' for command
  # executable completeions or 'default' for default completions.

  local command completion_function last_word next_to_last_word
  local COMP_CWORD COMP_LINE COMP_POINT COMP_WORDS COMPREPLY=()

  (( $# )) || {
    printf '\n'
    return
  }

  command=$1
  COMP_WORDS=( "$@" )

  # Get the command specific completion function.
  set -- $(complete -p "$command" 2>/dev/null)
  if (( ! $# )); then
    # Load the completion function for the command.
    _completion_loader "$command"
    set -- $(complete -p "$command" 2>/dev/null)
  fi
  # Check if it was loaded.
  if (( $# )); then
    # There is an explicit completer.
    shift $(( $# - 2 ))
    completion_function=$1
  else
    # Use the coshell default completer.
    __coshell_get_file_completions__ "${COMP_WORDS[${#COMP_WORDS[*]}-1]}"
    return
  fi

  # Set up the completion call stack -- really, this is the api?
  COMP_LINE=${COMP_WORDS[@]}
  COMP_POINT=${#COMP_LINE}

  # Index and value of the last word.
  COMP_CWORD=$(( ${#COMP_WORDS[@]} - 1 ))
  last_word=${COMP_WORDS[$COMP_CWORD]}

  # Value of the next to last word.
  if (( COMP_CWORD >= 2 )); then
    next_to_last_word=${COMP_WORDS[$((${COMP_CWORD}-1))]}
  else
    next_to_last_word=''
  fi

  # Execute the completion function. Some completers, like _python_argcomplete,
  # require $1, $2 and $3.
  if $completion_function "${command}" "${last_word}" "${next_to_last_word}" 2>/dev/null; then
    # Print the completions to stdout.
    printf '%s\n' "${COMPREPLY[@]}" ''
  else
    # Fall back to the coshell default completer on error.
    __coshell_get_file_completions__ "${COMP_WORDS[${#COMP_WORDS[@]}-1]}"
  fi
}

__coshell_get_executable_completions__() {
  # Prints the executable completions for $1 one per line, terminated by a
  # blank line sentinel.
  compgen -A command -- "$1"
  printf '\n'
}

__coshell_get_file_completions__() {
  # Prints the file completions for $1, with trailing / for dirs, one per line,
  # terminated by a blank line sentinel. We could almost use_filedir_xspec, but
  #   * it's not installed/sourced by default on some systems (like macos)
  #   * it's part of a ~2K line rc file with no clear way of slicing it out
  #   * ~ and $... are expanded in the completions
  if __coshell_var_brace_expand "$1"; then
    # ...$AB
    compgen -A variable -P "${1%\$*}\${" -S "}" -- "${1##*\$\{}"
  elif __coshell_var_plain_expand "$1"; then
    # ...${AB
    compgen -A variable -P "${1%\$*}\$" -- "${1##*\$}"
  else
    local word_raw word_exp word words=() x IFS=$'\n'
    word_raw=$1
    eval word_exp=\"$word_raw\"
    if [[ $word_exp == "$word_raw" ]]; then
      # No $... expansions, just add trailing / for dirs.
      words=( $(compgen -A file -- "$word_exp") )
      for word in ${words[@]}; do
        if [[ $word != */ ]]; then
          if [[ $word == \~* ]]; then
            eval x="$word"
          else
            x=$word
          fi
          [[ -d $x ]] && word+=/
        fi
        printf '%s\n' "$word"
      done
    else
      # $... expansions: expand for -d tests, return unexpanded completions with
      # trailing / for dirs. compgen -A file handles ~ but does not expand it,
      # too bad it doesn't do the same for $... expansions.
      local prefix_exp suffix_raw
      __coshell_suffix_raw "$word_raw"  # Sets suffix_raw.
      prefix_raw=${word_raw%"$suffix_raw"}
      prefix_exp=${word_exp%"$suffix_raw"}
      words=( $(compgen -A file "$word_exp") )
      for word in ${words[@]}; do
        [[ $word != */ && -d $word ]] && word+=/
        printf '%s\n' "${prefix_raw}${word#"$prefix_exp"}"
      done
    fi
  fi
  printf '\n'
}

__coshell_get_directory_completions__() {
  # Prints the directory completions for $1, with trailing /, one per line,
  # terminated by a blank line sentinel.
  if __coshell_var_brace_expand "$1"; then
    # ...$AB
    compgen -A variable -P "${1%\$*}\${" -S "}" -- "${1##*\$\{}"
  elif __coshell_var_plain_expand "$1"; then
    # ...${AB
    compgen -A variable -P "${1%\$*}\$" -- "${1##*\$}"
  else
    local word_raw word_exp word words=() x IFS=$'\n'
    word_raw=$1
    eval word_exp=\"$word_raw\"
    if [[ $word_exp == "$word_raw" ]]; then
      # No $... expansions, just add trailing / for dirs.
      words=( $(compgen -A directory -S/ -- "$word_exp") )
      printf '%s\n' "${words[@]}"
    else
      # $... expansions: return unexpanded completions with trailing /.
      local prefix_exp suffix_raw
      __coshell_suffix_raw "$word_raw"  # Sets suffix_raw.
      prefix_raw=${word_raw%"$suffix_raw"}
      prefix_exp=${word_exp%"$suffix_raw"}
      words=( $(compgen -A file -S/ -- "$word_exp") )
      for word in ${words[@]}; do
        printf '%s\n' "${prefix_raw}${word#"$prefix_exp"}"
      done
    fi
  fi
  printf '\n'
}

__coshell_default_completer__() {
  # The default interactive completer. Handles ~ and embedded $... expansion.
  local IFS=$'\n' completer=__coshell_get_file_completions__
  for o in "$@"; do
    case $o in
    -c) completer=__coshell_get_executable_completions__ ;;
    -d) completer=__coshell_get_directory_completions__ ;;
    esac
  done
  COMPREPLY=( $($completer "$cur") )
}

__coshell_init_completions__() {
  # Loads bash-completion if necessary.

  declare -F _completion_loader &>/dev/null || {
    source /usr/share/bash-completion/bash_completion 2>/dev/null || {
      _completion_loader() {
        return 1
      }
    }
  }

  # Defines bash version dependent functions.

  local x y

  x='${HOME}/tmp'
  y=${x##*\$?(\{)+([a-zA-Z0-90-9_])?(\})}
  if [[ $x != $y ]]; then
    # Modern bash.
    eval '
      __coshell_suffix_raw() {
        coshell_suffix_raw=${1##*\$?(\{)+([a-zA-Z0-90-9_])?(\})}
      }
    '
  else
    __coshell_suffix_raw() {
      suffix_raw=$(sed 's/.*\${*[a-zA-Z0-9_]*}*//' <<<"$1")
    }
  fi

  if eval '[[ x == *\$\{*([a-zA-Z0-90-9_]) ]]' 2>/dev/null; then
    # Modern bash.
    eval '
      __coshell_var_brace_expand() {
        [[ $1 == *\$\{*([a-zA-Z0-90-9_]) ]]
      }
      __coshell_var_plain_expand() {
        [[ $1 == *\$+([a-zA-Z0-90-9_]) ]]
      }
    '
  else
    __coshell_var_brace_expand() {
      __coshell_partial_expand=$(sed 's/.*\$\({*\)[a-zA-Z0-9_]*$/\1/' <<<"$1")
      [[ $1 && $__coshell_partial_expand == "{" ]]
    }
    __coshell_var_plain_expand() {
      __coshell_partial_expand=$(sed 's/.*\$\({*\)[a-zA-Z0-9_]*$/\1/' <<<"$1")
      [[ $1 && $__coshell_partial_expand == "" ]]
    }
  fi

  _filedir() {
    # Overrides the bash_completion function that completes internal $cur.
    __coshell_default_completer__ "$@"
  }

  _minimal() {
    # Overrides the bash_completion function that completes external COMP_WORDS.
    cur=${COMP_WORDS[$COMP_CWORD]}
    __coshell_default_completer__ "$@"
  }

  compopt() {
    # $completion_function is called by __coshell_get_file_completions__
    # outside a completion context. Any of those functions calling compopt will
    # get an annoying error and completely break completions. This override
    # ignores the errors -- the other coshell completer overrides should wash
    # them out.
    command compopt "$@" 2>/dev/null
    return 0
  }

}

__coshell_init_completions__
c                   0   ^  \ rS rSrSrSU 4S jjrSrU =r$ )CoshellExitErrori2  zThe coshell exited.c                 8   > [         [        U ]  U5        X l        g N)superr	   __init__status)selfmessager   	__class__s      5lib/googlecloudsdk/command_lib/interactive/coshell.pyr   CoshellExitError.__init__5  s    	
D*73K    r   r   )__name__
__module____qualname____firstlineno____doc__r   __static_attributes____classcell__r   s   @r   r	   r	   2  s     r   r	   c                       \ rS rSrSrSS jr\S 5       r\S 5       r\S 5       r	\
S 5       rS rS	 rS
 rS r\R"                  SS j5       r\R"                  S 5       rSS jrSS jrSrg)_CoshellBasei:  at  The local coshell base class.

Attributes:
  _edit_mode: The coshell edit mode, one of {'emacs', 'vi'}.
  _ignore_eof: True if the coshell should ignore EOF on stdin and not exit.
  _set_modes_callback: Called when SetModesCallback() is called or when
    mutable shell modes may have changed.
  _state_is_preserved: True if shell process state is preserved across Run().
c                 n    S U l         [        R                  " 5       U l        Xl        SU l        SU l        g )NemacsF)_set_modes_callbacklocalegetpreferredencoding	_encoding_state_is_preserved
_edit_mode_ignore_eof)r   state_is_preserveds     r   r   _CoshellBase.__init__E  s/    #D002DN1DODr   c                     U R                   $ r   )r'   r   s    r   	edit_mode_CoshellBase.edit_modeN  s    ??r   c                     U R                   $ r   )r(   r,   s    r   
ignore_eof_CoshellBase.ignore_eofR  s    r   c                     U R                   $ r   )r&   r,   s    r   r)   _CoshellBase.state_is_preservedV  s    ###r   c                 *    U c  Sn U $ U S:  a  SU -
  n U $ )z<Returns the shell $? status given a python Popen returncode.r       r   s    r   _ShellStatus_CoshellBase._ShellStatusZ  s,     ~f M 
!V|fMr   c                 j     UR                  U R                  5      $ ! [        [        4 a    Us $ f = f)z<Decodes external data if needed and returns internal string.)decoder%   AttributeErrorUnicodeError)r   datas     r   _Decode_CoshellBase._Decodec  s3    [[((L) ks    22c                 ^     UR                  U R                  5      $ ! [         a    Us $ f = f)z<Encodes internal string if needed and returns external data.)encoder%   r<   )r   strings     r   _Encode_CoshellBase._Encodej  s.    ]]4>>** ms    ,,c                     g)8Closes the coshell connection and release any resources.Nr6   r,   s    r   Close_CoshellBase.Closeq      r   c                 .    Xl         U(       a  U" 5         gg)zSets the callback function to be called when any mutable mode changed.

If callback is not None then it is called immediately to initialize the
caller.

Args:
  callback: func() called when any mutable mode changed, None to disable.
N)r"   )r   callbacks     r   SetModesCallback_CoshellBase.SetModesCallbacku  s      (j r   c                     g)aO  Runs command in the coshell and waits for it to complete.

Args:
  command: The command line string to run. Must be a sytactically complete
    shell statement. Nothing is executed if there is a syntax error.
  check_modes: If True runs self._GetModes() after command has executed if
    command contains `set -o ...` or `set +o ...`.
Nr6   r   commandcheck_modess      r   Run_CoshellBase.Run  s     	r   c                     gz*Sends the interrupt signal to the coshell.Nr6   )r   sigs     r   	Interrupt_CoshellBase.Interrupt       	r   c                     Ag)zReturns the list of completion choices for args.

Args:
  args: The list of command line argument strings to complete.
  prefix: Complete the last arg as a command prefix.
Nr6   )r   argsprefixs      r   GetCompletions_CoshellBase.GetCompletions  s
     	r   c                     A/ $ )Runs args and returns the list of output lines, up to first empty one.

Args:
  args: The list of command line arguments.
  quote: Shell quote args if True.

Returns:
  The list of output lines from command args up to the first empty line.
r6   )r   r[   quotes      r   Communicate_CoshellBase.Communicate  s     	Ir   )r'   r%   r(   r"   r&   NTF)r   r   r   r   r   r   propertyr-   r0   r)   staticmethodr7   r>   rC   rG   rL   abcabstractmethodrR   rW   r]   rb   r   r6   r   r   r   r   :  s         $ $  	 		 		 	 	r   r   c                      ^  \ rS rSrSrSrSrSrU 4S jr\	S 5       r
S rS	 rS
 rS rS rS rS rS rS r\R*                  SS j5       rSS jrSS jrS rSrU =r$ )_UnixCoshellBasei  zYThe unix local coshell base class.

Attributes:
  _shell: The coshell subprocess object.
x	      c                 T   > [         [        U ]  5         S U l        S U l        S U l        g r   )r   rk   r   r   
_status_fd_shellr   r   s    r   r   _UnixCoshellBase.__init__  s&    	
D*,DKDODKr   c                 D    SR                  U R                  SS5      5      $ )z?Quotes command in single quotes so it can be eval'd in coshell.z'{}''z'\'')formatreplace)rP   s    r   _Quote_UnixCoshellBase._Quote  s     ==g677r   c                      U R                  S5        U R	                  U R
                  R                  5      n[        SR                  U5      US9e! [        [        [        4 a     NUf = f)z"Raises the coshell exit exception.:zThe coshell exited [status={}].r   )	
_WriteLineIOErrorOSError
ValueErrorr7   rq   
returncoder	   rv   )r   r   s     r   _Exited_UnixCoshellBase._Exited  sh    
ooc t{{556F
)008 	 Wj) 
s   A A)(A)c                     U R                  U R                  R                  R                  5       5      R	                  5       $ )z;Reads and returns a decoded stripped line from the coshell.)r>   rq   stdoutreadlinestripr,   s    r   	_ReadLine_UnixCoshellBase._ReadLine  s-    <<**3356<<>>r   c                 D    [         R                  " U R                  S5      $ )zCReads and returns one encoded character from the coshell status fd.   )osreadrp   r,   s    r   _ReadStatusChar _UnixCoshellBase._ReadStatusChar  s    774??A&&r   c                 ^    U R                   R                  U R                  US-   5      5        g)z&Writes an encoded line to the coshell.
N)rq   communicaterC   )r   lines     r   r|   _UnixCoshellBase._WriteLine  s!    KKDLL56r   c                     U R                   R                  R                  U R                  US-   5      5        U R                   R                  R	                  5         g! [
        [        [        4 a    U R                  5          gf = f)z+Sends command to the coshell for execution.r   N)	rq   stdinwriterC   flushr}   r~   r   r   )r   rP   s     r   _SendCommand_UnixCoshellBase._SendCommand  sa    
kkdll7T>:;
kkWj) 
llns   AA %BBc                 B   / nU R                   R                  S5      n U R                  5       nUSSU4;   a  OUR                  U5        M-  U R	                  SR                  U5      5      nUR                  5       (       a  X2:X  a  U R                  5         [        U5      $ )8Gets the status of the last command sent to the coshell.asciiN   
r   )	SHELL_STATUS_EXITrA   r   appendr>   joinisdigitr   int)r   r   shell_status_exitcstatus_strings        r   
_GetStatus_UnixCoshellBase._GetStatus  s    D..55g>




 a	
tU-.	.
kk!n	 
 LL$0M  ""a&<
lln}r   c                 V   SnU R                  SSS9S:X  a  U R                  S:w  a	  SnSU l        OU R                  S:w  a	  SnSU l        U R                  nU R                  SSS9S:H  U l        U R                  U:w  a  SnU(       a#  U R                  (       a  U R                  5         g	g	g	)
zSyncs the user settable modes of interest to the Coshell.

Calls self._set_modes_callback if it was specified and any mode changed.
Fzset -o | grep -q "^vi.*on"rQ   r   viTr!   z!set -o | grep -q "^ignoreeof.*on"N)rR   r'   r(   r"   )r   changedr0   s      r   	_GetModes_UnixCoshellBase._GetModes  s     G xx,%x@AE	D	 	G	#! !!Jxx+   @CDED:%g4++
  ,wr   c                     U R                  S/SS9n[        U5      S:X  a   [        R                  " US   5        US   $ g! [         a     gf = f)zEGets the coshell pwd, sets local pwd, returns the pwd, None on error.zprintf "$PWD\n\n"F)ra   r   r   N)rb   lenr   chdirr~   )r   pwds     r   GetPwd_UnixCoshellBase.GetPwd  s`    


01

?C
3x1}
Q1v   s   A 
AAc           	         U R                  SR                  [        U R                  U R                  [
        S95        U R                  S5        U R                  S5        U R                  5         U R                  S5        g)z,Consults the user shell config for defaults.zCOSHELL_VERSION={coshell_version};_status() {{ return $1; }};[[ -f $HOME/.bashrc ]] && source $HOME/.bashrc;trap 'echo $?{exit} >&{fdstatus}' 0;trap ":" 2;{get_completions_init})coshell_versionexitfdstatusget_completions_initzset -o monitor 2>/dev/nullz#shopt -s expand_aliases 2>/dev/nulltrueN)r   rv   COSHELL_VERSIONr   SHELL_STATUS_FD_GET_COMPLETIONS_INITr   r,   s    r   _GetUserConfigDefaults'_UnixCoshellBase._GetUserConfigDefaults  s}     			, 
++--%: 
 
<=$ 	23 	;< 	NN 	fr   c                     g)9Runs command in the coshell and waits for it to complete.Nr6   rO   s      r   _Run_UnixCoshellBase._Run7  rY   r   c                 N   Sn[         R                   " [         R                  [         R                  5      n U R                  XS9n[         R                   " [         R                  U5        U$ ! [         a     N3f = f! [         R                   " [         R                  U5        f = f)r      r   )signalSIGINTSIG_IGNr   KeyboardInterrupt)r   rP   rQ   r   sigints        r   rR   _UnixCoshellBase.Run<  sv    F]]6==&..9F+yyy:f mmFMM6*M	  
 mmFMM6*s#   A- -
A:7A= 9A::A= ='B$c                     U(       a  U R                  SUS   /5      nOU R                  S/U-   5      n[        [        U5      5      $ )zReturns the list of completion choices for args.

Args:
  args: The list of command line argument strings to complete.
  prefix: Complete the last arg as a command prefix.

Returns:
  The list of completions for args.
&__coshell_get_executable_completions____coshell_get_completions__)rb   sortedset)r   r[   r\   completionss       r   r]   _UnixCoshellBase.GetCompletionsH  sQ     $$&N&*2h&0 1k $$&C%Dt%KLk#k"##r   c                 V    U R                   R                  [        R                  5        grU   )rq   send_signalr   r   r,   s    r   rW   _UnixCoshellBase.InterruptZ  s    KKFMM*r   )r'   r(   rq   rp   r   rd   re   )r   r   r   r   r   r   r   SHELL_STDIN_FDr   rg   rx   r   r   r   r|   r   r   r   r   r   rh   ri   r   rR   r]   rW   r   r   r   s   @r   rk   rk     s     /. 8 8
?'7!8	@ 	 	
$$+ +r   rk   c                   N   ^  \ rS rSrSrSrS	U 4S jjrS rS
S jrS
S jr	Sr
U =r$ )_UnixCoshelli_  a  The unix local coshell implementation.

This implementation preserves coshell process state across Run().

Attributes:
  _status_fd: The read side of the pipe where the coshell write 1 char status
    lines. The status line is used to mark the exit of the currently running
    command.
z	/bin/bashc           	        > [         [        U ]  5          [        R                  " U R
                  5      n[        R                  " SU R
                  5         [        R                  " U R                  5      n[        R                  " SU R                  5        [        R                  " 5       u  U l
        n[        R                  " XPR
                  5        [        R                  " U5        [        R                  " [        R                  [        5      nU(       a  UR!                  S5      nOU R"                  /n[$        R&                  (       a  0 OSS0n[(        R*                  " U4[        R                  [(        R,                  UUSS.UD6U l        US:  a7  [        R                  " X0R
                  5        [        R                  " U5        O [        R                  " U R
                  5        US:  a7  [        R                  " X@R                  5        [        R                  " U5        O [        R                  " U R                  5        U R1                  5         g ! [         a    Sn GN8f = f! [         a    Sn GN	f = f)Nr   r   r    restore_signalsF)envr   r   stderr	close_fds)r   r   r   r   dupr   r~   dup2r   piperp   closer   GetEncodedValueenvironCOSHELL_ENVsplit
SHELL_PATHsixPY2
subprocessPopenPIPErq   r   )
r   r   r   caller_shell_status_fdcaller_shell_stdin_fdwcoshell_command_lineshell_commandadditional_kwargsr   s
            r   r   _UnixCoshell.__init__l  s   	,&("!vvd&:&:; GGAt##$! ffT%8%89 GGAt""#DOQGGA##$HHQK $33BJJL*005m'm "gg,=u+E""JJoo DK "gg$&:&:;hh%&hht##$!gg#%8%89hh$%hht""#!c  "!"  ! !s#    I  I1 I.-I.1J Jc                 
   U R                   S:  a'  [        R                  " U R                   5        SU l          U R                  S5        U R                  U R                  R                  5      $ ! [        [
        4 a     N7f = f)rF   r   r   r   )	rp   r   r   r|   r}   r   r7   rq   r   r,   s    r   rG   _UnixCoshell.Close  sl    !hhtdo
oof T[[3344 Z  
s   A/ /BBc                 j   U R                  SR                  U R                  U5      U R                  U R                  S95        U R                  5       nU(       aX  [        R                  " SU5      (       a  U R                  5         [        R                  " SU5      (       a  U R                  5         U$ )r   zwcommand eval {command} <&{fdin} && echo 0 >&{fdstatus} || {{ status=$?; echo $status 1>&{fdstatus}; _status $status; }})rP   r   fdin\bset\s+[-+]o\s+\w\bcd\b)
r   rv   rx   r   r   r   researchr   r   r   rP   rQ   r   s       r   r   _UnixCoshell._Run  s    	HHNKK())$$ IO I&' __F 	('	2	2	9g	&	&Mr   c                 6   U(       a1  SR                  U Vs/ s H  o0R                  U5      PM     sn5      nOSR                  U5      nU R                  SR                  X@R                  S95        / n/ n  U R                  5       nWS;   aJ  U(       d   U$ UR                  U R                  SR                  U5      R                  5       5      5        / nOUR                  U5        Mt  s  snf ! [        [        [        4 a    U R                  5          Nf = f)r`   r   z{command} >&{fdstatus}
)rP   r   )Nr   r   )r   rx   r   rv   r   r   r}   r~   r   r   r   r>   rstrip)r   r[   ra   argrP   linesr   r   s           r   rb   _UnixCoshell.Communicate  s     d;ds++c*d;<gg077"6"6 8 8 9ED
  " 
m	

 L	 	T\\#((4."7"7"9:;A  < w
+ s   C+8C0 0%DD)rq   rp   )r      rd   )r   r   r   r   r   r   r   rG   r   rb   r   r   r   s   @r   r   r   _  s)     *8"t
5& r   r   c                   d   ^  \ rS rSrSrSrSrSrU 4S jrS r	S r
S rSS	 jrSS
 jrS rSrU =r$ )_MinGWCoshelli  a{  The MinGW local coshell implementation.

This implementation preserves coshell process state across Run().

NOTE: The Windows subprocess module passes fds 0,1,2 to the child process and
no others. It is possble to pass handles that can be converted to/from fds,
but the child process needs to know what handles to convert back to fds. Until
we figure out how to reconstitute handles as fds >= 3 we are stuck with
restricting fds 0,1,2 to be /dev/tty, via shell redirection, for Run(). For
internal communication fds 0,1 are pipes. Luckily this works for the shell
interactive prompt. Unfortunately this fails for the test environment.
Nz/dev/ttyc                 t   > [         [        U ]  5         U R                  5       U l        U R                  5         g r   )r   r  r   _Popenrq   r   rr   s    r   r   _MinGWCoshell.__init__  s)    	-')++-DK!r   c                     [         R                  " 5       n[         R                  Ul        [         R                  " U R
                  /[         R                  [         R                  US9$ )z2Mockable popen+startupinfo so we can test on Unix.)r   r   startupinfo)r   STARTUPINFOCREATE_NEW_PROCESS_GROUPdWflagsr   r   r   )r   r
  s     r   r  _MinGWCoshell._Popen  sK    ((*K$==KT__-",//#-??(35 5r   c                      U R                  S5        U R                  U R                  R
                  5      $ ! [        [        4 a     N7f = f)rF   r   )r|   r}   r   r7   rq   r   r,   s    r   rG   _MinGWCoshell.Close  sI    
oof T[[3344 Z  
s   8 A
Ac                    U R                  5       nUR                  U R                  5      (       a  U R                  nUSS nOSnUR                  5       (       a  X R                  :X  a  U R	                  5         [        U5      $ )r   Nr    )r   endswithr   r   r   r   )r   r   r   s      r   r   _MinGWCoshell._GetStatus  so    NN$Md4455

 
 a#CR(m
a  ""a+A+A&A
lln}r   c                 j   U R                  SR                  U R                  U5      U R                  U R                  S95        U R                  5       nU(       aX  [        R                  " SU5      (       a  U R                  5         [        R                  " SU5      (       a  U R                  5         U$ )r   zdcommand eval {command} <'{stdin}' >>'{stdout}' && echo 0 || {{ status=$?; echo 1; (exit $status); }})rP   r   r   r   r   )
r   rv   rx   
STDIN_PATHSTDOUT_PATHr   r   r   r   r   r   s       r   r   _MinGWCoshell._Run  s    	3396KK(//## 4: 4
 __F 	('	2	2	9g	&	&Mr   c                 ~   U(       a1  SR                  U Vs/ s H  o0R                  U5      PM     sn5      nOSR                  U5      nU R                  US-   5        / n  U R                  5       nW(       d   U$ UR                  U5        M.  s  snf ! [        [
        [        4 a    U R                  5          NIf = f)r`   r   r   )	r   rx   r   r   r}   r~   r   r   r   )r   r[   ra   r   rP   r  r   s          r   rb   _MinGWCoshell.Communicate0  s     d;ds++c*d;<gggn%E
~~ L ll4  < w
+ s   B"B %B<;B<c                 V    U R                   R                  [        R                  5        grU   )rq   r   r   CTRL_C_EVENTr,   s    r   rW   _MinGWCoshell.InterruptK  s    KKF//0r   )rq   rd   )r   r   r   r   r   r   r  r  r   r  rG   r   r   rb   rW   r   r   r   s   @r   r  r    sA     **+"
55
(61 1r   r  c                   <   ^  \ rS rSrSrU 4S jrSS jrS rSrU =r	$ )_WindowsCoshelliP  zuThe windows local coshell implementation.

This implementation does not preserve shell coprocess state across Run().
c                 (   > [         [        U ]  SS9  g )NF)r)   )r   r  r   rr   s    r   r   _WindowsCoshell.__init__V  s    	/4)U)Cr   c                 .    A[         R                  " USS9$ )r   T)shell)r   callrO   s      r   rR   _WindowsCoshell.RunY  s    ??7$//r   c                     grU   r6   r,   s    r   rW   _WindowsCoshell.Interrupt^  rI   r   r6   re   )
r   r   r   r   r   r   rR   rW   r   r   r   s   @r   r  r  P  s    
D0
	 	r   r  c                  B     [        [        5      $ ! [         a     gf = f)z#Lightweight mockable Windows check.F)boolWindowsError	NameErrorr6   r   r   _RunningOnWindowsr,  c  s$    	 s    
c                   "    \ rS rSrSrSrS rSrg)Coshellik  zThe local coshell implementation shim.

This shim class delays os specific checks until the first instantiation. The
checks are memoized in the shim class for subsequent instantiations.
Nc                 |   U R                   (       dp  [        5       (       aV  [        U l         S HD  n[        R                  R                  U5      (       d  M)  [        U l         X0R                   l          O   O[        U l         U R                   R                  " U R                   /UQ70 UD6nUR                  5         U$ )N)zC:\MinGW\bin\sh.exezC:\Program Files\Git\bin\sh.exe)_IMPLEMENTATIONr,  r  r   pathisfiler  r   r   __new__r   )clsr[   kwargsr#  objs        r   r3  Coshell.__new__t  s    			-
:EWW^^E"""/C-2*: +



%
%c&9&9
KD
KF
KCLLNJr   r6   )r   r   r   r   r   r0  r3  r   r6   r   r   r.  r.  k  s     /r   r.  )r   
__future__r   r   r   rh   r#   r   r   r   r   googlecloudsdk.core.utilr   r   r   r   r   	Exceptionr	   with_metaclassABCMetaobjectr   rk   r   r  r  r,  r.  r6   r   r   <module>r>     s    < '  ' 
  	 	   - 
p fy n3%%ckk6: nbq+s))#++|D q+hE# EPf1$ f1R	l 	&f r   