
    B=                     0   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J	r	  SSK
Jr  SSKrSSKJr  SS	KJr  S
rSrSrSrSrSr\S-   rSrSrSrSrSr " S S\5      rS rS rS r S r!S r"S r#S r$S(S jr%S)S  jr&S! r'S" r(S# r)S$ r*S% r+S& r,S' r-g)*z,Utilities for the `gcloud feedback` command.    )absolute_import)division)unicode_literalsN)log)console_attr_os)range)urllibz https://issuetracker.google.com/z*https://issuetracker.google.com/issues/newz>https://issuetracker.google.com/issues?q=componentid:187143%2Bi i   a  WARNING: This is a PUBLIC issue tracker, and as such, anybody can read the
information in the report you file. In order to help diagnose the issue,
we've included some installation information in this report. Please look
through and redact any information you consider personal or sensitive
before submitting this issue.

{formatted_command}What steps will reproduce the problem?


What is the expected output? What do you see instead?


Please provide any additional information below.


z@{formatted_traceback}


Installation information:

{gcloud_info}z[output truncated]   zv(?P<stacktrace>Traceback \(most recent call last\):\n(?: {2}File ".*", line \d+, in .+\n {4}.+\n)+)(?P<exception>\S.+)zTFile "(?P<file>.*)", line (?P<line>\d+), in (?P<function>.+)\n(?P<code_snippet>.+)\nP   c                       \ rS rSrS rSrg)CommentHolderY   c                 4    Xl         X l        X0l        X@l        g N)bodypre_stacktrace
stacktrace	exception)selfr   r   r   r   s        /lib/googlecloudsdk/command_lib/feedback_util.py__init__CommentHolder.__init__[   s    I( ON    )r   r   r   r   N)__name__
__module____qualname____firstlineno__r   __static_attributes__ r   r   r   r   Y   s    r   r   c                     U [         R                  " [        5      S.n[        S-   [        R
                  R                  U5      -   $ )N)description	component?)six	text_typeISSUE_TRACKER_COMPONENTNEW_ISSUE_URLr	   parse	urlencode)commentparamss     r   _FormatNewIssueUrlr,   b   s:    ==!89& 
	v||55f=	==r   c                 .    SS K nUR                  U 5        g )Nr   )
webbrowseropen_new_tab)urlr.   s     r   OpenInBrowserr1   j   s     #r   c                 `    [         R                  R                  SU 05      SS n[        U5      $ )z-Return the length of string when URL-encoded.    N)r	   r(   r)   len)stringencodeds     r   _UrlEncodeLenr8   r   s-     LL""B<04'	Wr   c                 4    SR                  U S/U-   5      S-   $ )N
z  [...])join)first_entryrests     r   _FormatStackTracer>   z   s     	K+d2	3d	::r   c           	         U R                  S5      n U R                  S5      n[        S[        U5      [        5       Vs/ s H  nSR                  X#U[        -    5      PM     nn[        U 5      U::  a  U S-   $ USS n[        [        US   U5      5      U:  aA  [        U5      S:  a2  USS n[        [        US   U5      5      U:  a  [        U5      S:  a  M2  [        US   U5      $ s  snf )a  Cut out the middle entries of the stack trace to a given length.

For instance:

>>> stacktrace = '''
...   File "foo.py", line 10, in run
...     result = bar.run()
...   File "bar.py", line 11, in run
...     result = baz.run()
...   File "baz.py", line 12, in run
...     result = qux.run()
...   File "qux.py", line 13, in run
...     raise Exception(':(')
... '''
>>> _ShortenStacktrace(stacktrace, 300) == '''  ...   File "foo.py", line 10, in run
...     result = bar.run()
...   [...]
...   File "baz.py", line 12, in run
...      result = qux.run()
...   File "qux.py", line 13, in run
...      raise Exception(':(')
... '''
True


Args:
  stacktrace: str, the stacktrace (might be formatted by _FormatTraceback)
      without the leading 'Traceback (most recent call last):' or 'Trace:'
  url_encoded_length: int, the length to shorten the stacktrace to (when
      URL-encoded).

Returns:
  str, the shortened stacktrace.
r:   r   r4   N)stripsplitr   r5   STACKTRACE_LINES_PER_ENTRYr;   r8   r>   )r   url_encoded_lengthlinesientriesr=   s         r   _ShortenStacktracerG   ~   s   R %*


4
 %1c%j"<=?= CDTYYuq!;;<== 
 ? :"44	$	(T:	;	
!$TQ8D 
(T:	;	
!$TQ
 
71:t	,,?s   $C*c                    U R                   R                  S5      u  p#nX4-   nU[        [        S-   5      -
  n[	        U R                   U5      u  pg[        U5      U::  a  Xg4$ [        U R
                  S-   U R                  -   S-   [        -   5      nX-
  n	[        U R                  U	5      n
U R
                  S-   U
-   U R                  -   S-   [        -   nSU R                  -   U R                  -   S-   U-   n[        U5      U::  a  UU4$ Xl4$ )a  Shortens the comment to be at most the given length (URL-encoded).

Does one of two things:

(1) If the whole stacktrace and everything before it fits within the
    URL-encoded max length, truncates the remainder of the comment (which
    should include e.g. the output of `gcloud info`.
(2) Otherwise, chop out the middle of the stacktrace until it fits. (See
    _ShortenStacktrace docstring for an example).
(3) If the stacktrace cannot be shortened to fit in (2), then revert to (1).
    That is, truncate the comment.

Args:
  comment: CommentHolder, an object containing the formatted comment for
      inclusion before shortening, and its constituent components
  url_encoded_length: the max length of the comment after shortening (when
      comment is URL-encoded).

Returns:
  (str, str): the shortened comment and a message containing the parts of the
  comment that were omitted by the shortening process.
zInstallation information:
r:   Trace:
zFull stack trace (formatted):
z

)	r   	partitionr8   TRUNCATED_INFO_MESSAGE_UrlTruncateLinesr   r   rG   r   )r*   rC   critical_infomiddleoptional_infomax_str_lentruncated_issue_body	remainingnon_stacktrace_encoded_lenmax_stacktrace_lenshortened_stacktrace'critical_info_with_shortened_stacktrace"optional_info_with_full_stacktraces                r   _ShortenIssueBodyrX      s_   6 *1)?)?#*%&-(- $5<=>+$5gllK$P! =![0** "/+g.?.??$F	"  ,H-g.@.@.@B 	+.BB	 	!#9	: , +L*1*<*<+=*1*;*;+<>D+E +8+8& <=L502 2 "EEr   c                    U R                  S5      n/ n/ nU[        [        S-   5      -
  nU(       ao  [        SR                  X2SS -   5      5      U::  aL  UR	                  UR                  S5      5        U(       a%  [        SR                  X2SS -   5      5      U::  a  ML  UnU(       a  UR	                  [        5        SR                  U5      SR                  U5      4$ )aK  Truncates the given string to the given URL-encoded length.

Always cuts at a newline.

Args:
  string: str, the string to truncate
  url_encoded_length: str, the length to which to truncate

Returns:
  tuple of (str, str), where the first str is the truncated version of the
  original string and the second str is the remainder.
r:   Nr4   r   )rA   r8   rK   r;   appendpop)r6   rC   rD   included_linesexcluded_linesrP   s         r   rL   rL      s     ,,t
%..#5<=>+		tyy)!;<	=	L%))A,' 
	tyy)!;<	=	L.01	>	"DIIn$=	==r   c                 r    U (       a  SU -   S-   n [         R                  " 5       u  pU R                  US5      $ )zReturn a console-width divider (ex: '======================' (etc.)).

Supports messages (ex: '=== Messsage Here ===').

Args:
  text: str, a message to display centered in the divider.

Returns:
  str, the formatted divider
 =)r   GetTermSizecenter)textwidth_s      r   
GetDividerrf     s6     
:D((*(%	UC	  r   c                    [         R                  " U 5      nSnU(       a,  UR                  (       a  SR                  UR                  5      n[        R                  US9nSnSnSnU(       a0  UR
                  (       a  [        UR
                  5      u  pgSU-   U-   n[        R                  X2R                  5       US9n[        XUU5      $ )ay  Construct a useful issue body with which to pre-populate the issue tracker.

Args:
  info: InfoHolder, holds information about the Cloud SDK install
  log_data: LogData, parsed log data for a gcloud run

Returns:
  CommentHolder, a class containing the issue comment body, part of comment
      before stacktrace, the stacktrace portion of the comment, and the
      exception
r3   zIssue running command [{0}].

)formatted_commandrI   )rh   gcloud_infoformatted_traceback)
r$   r%   commandformatCOMMENT_PRE_STACKTRACE_TEMPLATE	traceback_FormatTracebackCOMMENT_TEMPLATEr@   r   )	infolog_datari   rh   r   rj   formatted_stacktracer   comment_bodys	            r   _FormatIssueBodyru   &  s     d#+("":AA 399) : +. )($$ '7x7I7I&J#$';;iG!(()7H7H7J- ) /, 
|5I 
" "r   c                     U R                  S5      nU R                  S5      nU R                  S5      nUR                  5       S[         n[        U5      [        :  a  US-  nSR	                  XU5      nU$ )a?  Used in re.sub to format a stacktrace entry to make it more compact.

File "qux.py", line 13, in run      ===>      qux.py:13
  foo = math.sqrt(bar) / foo                   foo = math.sqrt(bar)...

Args:
  entry: re.MatchObject, the original unformatted stacktrace entry

Returns:
  str, the formatted stacktrace entry
filelinecode_snippetNz...z{0}:{1}
 {2}
)groupr@   MAX_CODE_SNIPPET_LENGTHr5   rl   )entryfilenameline_nory   formatted_code_snippetformatted_entrys         r   _StacktraceEntryReplacementr   N  s{     [[ (KK'^,,'--/0H1HI00e#%,,X-CE/	r   c                  "    [         R                  $ )z4Return the Python paths (can be mocked for testing).)syspathr   r   r   _SysPathr   f  s    	/r   c                     [        [        5       [        SS9nU HF  nU[        R                  R
                  -   nU R                  U5      (       d  M8  U [        U5      S  s  $    U $ )NT)keyreverse)sortedr   r5   osr   sep
startswith)r   python_pathspython_pathprefixs       r   _StripLongestSysPathr   k  sU    
T:,!k277;;&Fv#f+, " 
+r   c                     S[         R                  R                  -   nU R                  U5      (       a  U [	        U5      S  $ U $ )Ngooglecloudsdk)r   r   r   r   r5   )r   r   s     r   _StripCommonDirr   t  s8    bggkk)&#v66c&kl	@D@r   c                 d    [        [        R                  R                  [	        U 5      5      5      $ )zERemoves common elements (sys.path, common SDK directories) from path.)r   r   r   normpathr   )r   s    r   
_StripPathr   y  s"    	))*>t*DE	FFr   c                    [         R                  " [        U 5      nU(       d  U S4$ UR                  S5      nUR                  S5      nSR	                  S UR                  5        5       5      nUS-  n[         R                  " SU5      nU H  nUR                  U[        U5      5      nM      [         R                  " [        [        U5      nUR                  SS5      nXC4$ )zCompacts stack trace portion of traceback and extracts exception.

Args:
  traceback: str, the original unformatted traceback

Returns:
  tuple of (str, str) where the first str is the formatted stack trace and the
  second str is exception.
r3   r   r   r:   c              3   @   #    U  H  oR                  5       v   M     g 7fr   )r@   ).0rx   s     r   	<genexpr>#_FormatTraceback.<locals>.<genexpr>  s      #<#: 59::<<#:s   zFile "(.*)"z#Traceback (most recent call last):
)researchPARTITION_TRACEBACK_PATTERNrz   r;   
splitlinesfindallreplacer   subTRACEBACK_ENTRY_REGEXPr   )rn   matchr   r   rs   stacktrace_filesr   s          r   ro   ro   ~  s     ))/
;%	b={{<(*kk+&)  #<#-#8#8#:#< <$ZZ
;d/77j>NO   6 ; 46 .55,b2 
	((r   c                 D   [        X5      n[        UR                  5      n[        U5      [        :  a  [        [        [        S5      5      -
  n[        X$5      u  pV[        R                  " S5        Sn[        R                  R                  [        U5      5        [        R                  R                  UR                  5       5        [        R                  R                  [        SU-   5      5        [        R                  " S5        [        R                  " S5        [        U5      n[        U5        [        R                  R                  S5        [        R                  R                  S[        -  5        [        R                  R                  S	[        -  5        g
)zOpens a new tab in the web browser to the new issue page for Cloud SDK.

The page will be pre-populated with relevant information.

Args:
  info: InfoHolder, the data from of `gcloud info`
  log_data: LogData, parsed representation of a recent log
r3   zITruncating included information. Please consider including the remainder:z1TRUNCATED INFORMATION (PLEASE CONSIDER INCLUDING)zEND zIThe output of gcloud info is too long to pre-populate the new issue form.z0Please consider including the remainder (above).z5Opening your browser to a new Google Cloud SDK issue.zIf your browser does not open or you have issues loading the web page, please ensure you are signed into your account on %s first, then try again.zGIf you still have issues loading the web page, please file an issue: %sN)ru   r,   r   r5   MAX_URL_LENGTHrX   r   warningstatusPrintrf   r@   r1   ISSUE_TRACKER_BASE_URLISSUE_TRACKER_URL)rq   rr   r*   r0   max_info_len	truncatedrR   divider_texts           r   OpenNewIssueInBrowserr     s-    T,'7<<(#X!C(:2(>$??L,WCIKK ; <FLJJZ-.JJY__&'JJZ 567KK " #KKBC
Y
'C**JK**'() **Or   )r3   r   ).__doc__
__future__r   r   r   r   r   r   googlecloudsdk.corer   googlecloudsdk.core.consoler   r$   	six.movesr   r	   r   r'   r   r&   r   rm   rp   rK   rB   r   r   r{   objectr   r,   r1   r8   r>   rG   rX   rL   rf   ru   r   r   r   r   r   ro   r   r   r   r   <module>r      s     3 &  ' 	 	 
 # 7 
  ; <T    # $ 3 6   .      F >;8-v=F@>8!"%"P0
A
G
$)N r   