1414# See the COPYING file in the top-level directory.
1515
1616import datetime
17- import errno
1817import getpass
1918import json
2019import logging
2827
2928import requests .exceptions
3029
31- import bugzilla
32-
3330import bugzilla
3431from ._cli import _is_unittest_debug
3532from ._cli import open_without_clobber
9188HANDLE_LOGIN_Y = 0
9289HANDLE_LOGIN_N = 1
9390
91+ class InterruptLoop (Exception ): pass
9492
9593################
9694# Patch output #
@@ -122,6 +120,7 @@ def exit_patched(self, status=0, message=None):
122120 emsg = message + \
123121 "\n ArgumentParser exit with status {}" .format (status )
124122 self ._print_message (emsg )
123+ raise InterruptLoop
125124
126125class Bugzilla_patched (bugzilla .Bugzilla ):
127126 """ Patch `bugzilla.Bugzilla` to fit MI
@@ -196,7 +195,7 @@ def interactive_login(self, user=None, password=None, force=False,
196195# Util helpers #
197196################
198197
199- def setup_logging (debug , verbose ):
198+ def setup_logging ():
200199 """ Patch for redirecting log into file
201200
202201 Avoid interfering with the contents in
@@ -208,6 +207,9 @@ def setup_logging(debug, verbose):
208207 datefmt = "%y.%m.%d %H:%M:%S" ))
209208 log .addHandler (handler )
210209
210+ def level_logging (debug , verbose ):
211+ """ Change log level on the fly
212+ """
211213 if debug :
212214 log .setLevel (logging .DEBUG )
213215 elif verbose :
@@ -492,121 +494,154 @@ def _handle_login(opt, action, bz):
492494 password = getattr (opt , "pos_password" , None ) or opt .password
493495 use_key = getattr (opt , "api_key" , False )
494496
495- try :
496- if use_key :
497- bz .interactive_save_api_key ()
498- elif do_interactive_login :
499- swrite (FLAG_HEAD_ILOGIN )
500- if bz .api_key :
501- swrite ("You already have an API key configured for %s" % bz .url )
502- swrite ("There is no need to cache a login token. Exiting." )
503- swrite (FLAG_TAIL_ILOGIN )
504- sflush ()
505- return HANDLE_LOGIN_Y
506- swrite ("Logging into %s" % urllib .parse .urlparse (bz .url )[1 ])
497+ if use_key :
498+ bz .interactive_save_api_key ()
499+ elif do_interactive_login :
500+ swrite (FLAG_HEAD_ILOGIN )
501+ if bz .api_key :
502+ swrite ("You already have an API key configured for %s" % bz .url )
503+ swrite ("There is no need to cache a login token. Exiting." )
507504 swrite (FLAG_TAIL_ILOGIN )
508505 sflush ()
509- bz .interactive_login (username , password ,
510- restrict_login = opt .restrict_login )
511- except bugzilla .BugzillaError as e :
512- swrite (FLAG_HEAD_EXCEPT )
513- swrite ("Hit bugzilla.BugzillaError: %s" % str (e ))
514- swrite (FLAG_TAIL_EXCEPT )
506+ raise InterruptLoop (HANDLE_LOGIN_Y )
507+ swrite ("Logging into %s" % urllib .parse .urlparse (bz .url )[1 ])
508+ swrite (FLAG_TAIL_ILOGIN )
515509 sflush ()
516- return HANDLE_LOGIN_N
510+ bz .interactive_login (username , password ,
511+ restrict_login = opt .restrict_login )
517512
518513 if opt .ensure_logged_in and not bz .logged_in :
519- print ("--ensure-logged-in passed but you aren't logged in to %s" %
520- bz .url )
521- return HANDLE_LOGIN_N
514+ swrite (FLAG_HEAD_ILOGIN )
515+ swrite ("--ensure-logged-in passed but you aren't logged in to %s" % bz .url )
516+ swrite (FLAG_TAIL_ILOGIN )
517+ sflush ()
518+ raise InterruptLoop (HANDLE_LOGIN_N )
522519
523520 if is_login_command :
524- return HANDLE_LOGIN_Y
521+ raise InterruptLoop ( HANDLE_LOGIN_Y )
525522
526523
527524def _main (unittest_bz_instance ):
525+ """ (Patched version)
526+ """
527+ # init argparser & logger
528+ setup_logging ()
528529 parser = setup_parser ()
529- opt = parser .parse_args ()
530- action = opt .command
531- setup_logging (opt .debug , opt .verbose )
532-
533- log .debug ("Launched with command line: %s" , " " .join (sys .argv ))
534- log .debug ("Bugzilla module: %s" , bugzilla )
535-
536- if unittest_bz_instance :
537- bz = unittest_bz_instance
538- else :
539- bz = _make_bz_instance (opt )
540-
541- # Handle login options
542- _handle_login (opt , action , bz )
530+ refresh = False
543531
532+ # main loop
533+ while True :
534+ swrite (FLAG_HEAD_ARGINF )
535+ swrite ("ArgumentParser waiting" )
536+ swrite (FLAG_TAIL_ARGINF )
537+ sflush ()
544538
545- ###########################
546- # Run the actual commands #
547- ###########################
548-
549- if hasattr (opt , "outputformat" ):
550- if not opt .outputformat and opt .output not in ['raw' , 'json' , None ]:
551- opt .outputformat = _convert_to_outputformat (opt .output )
552-
553- buglist = []
554- if action == 'info' :
555- _do_info (bz , opt )
556-
557- elif action == 'query' :
558- buglist = _do_query (bz , opt , parser )
559-
560- elif action == 'new' :
561- buglist = _do_new (bz , opt , parser )
539+ try :
540+ NewCmd = sreadl ().strip ()
541+ if (NewCmd == "__REFRESH__" ):
542+ refresh = True
543+ continue
544+ NewOpt = parser .parse_args (NewCmd .split ())
545+ except InterruptLoop :
546+ continue
547+ level_logging (NewOpt .debug , NewOpt .verbose )
548+ log .debug ("Launched with command line: %s" , NewCmd )
549+ log .debug ("Bugzilla module: %s" , bugzilla )
550+ NewAct = NewOpt .command
562551
563- elif action == 'attach' :
564- if opt .get or opt .getall :
565- if opt .ids :
566- parser .error ("Bug IDs '%s' not used for "
567- "getting attachments" % opt .ids )
568- _do_get_attach (bz , opt )
552+ if unittest_bz_instance :
553+ bz = unittest_bz_instance
569554 else :
570- _do_set_attach (bz , opt , parser )
555+ bz = _make_bz_instance (NewOpt , force_new = refresh )
556+ refresh = False
571557
572- elif action == 'modify' :
573- _do_modify (bz , parser , opt )
574- else : # pragma: no cover
575- raise RuntimeError ("Unexpected action '%s'" % action )
558+ try :
559+ # Handle login options
560+ _handle_login (NewOpt , NewAct , bz )
561+ except InterruptLoop :
562+ continue
563+ except Exception as E :
564+ # not BaseException to jump KeyboardInterrupt
565+ swrite (FLAG_HEAD_EXCEPT )
566+ swrite ("Hit %s:\n %s" % (E .__class__ .__name__ ,str (E )))
567+ swrite (FLAG_TAIL_EXCEPT )
568+ sflush ()
569+ continue
576570
577- # If we're doing new/query/modify, output our results
578- if action in ['new' , 'query' ]:
579- _format_output (bz , opt , buglist )
571+ if hasattr (NewOpt , "outputformat" ):
572+ if not NewOpt .outputformat and NewOpt .output not in ['raw' , 'json' , None ]:
573+ NewOpt .outputformat = _convert_to_outputformat (NewOpt .output )
574+ buglist = []
575+ try :
576+ if NewAct == 'info' :
577+ _do_info (bz , NewOpt )
578+
579+ elif NewAct == 'query' :
580+ buglist = _do_query (bz , NewOpt , parser )
581+
582+ elif NewAct == 'new' :
583+ buglist = _do_new (bz , NewOpt , parser )
584+
585+ elif NewAct == 'attach' :
586+ if NewOpt .get or NewOpt .getall :
587+ if NewOpt .ids :
588+ parser .error ("Bug IDs '%s' not used for "
589+ "getting attachments" % NewOpt .ids )
590+ _do_get_attach (bz , NewOpt )
591+ else :
592+ _do_set_attach (bz , NewOpt , parser )
593+
594+ elif NewAct == 'modify' :
595+ _do_modify (bz , parser , NewOpt )
596+ else :
597+ continue
580598
599+ # If we're doing new/query/modify, output our results
600+ if NewAct in ['new' , 'query' ]:
601+ _format_output (bz , NewOpt , buglist )
602+ except InterruptLoop :
603+ continue
604+ except (xmlrpc .client .Fault , bugzilla .BugzillaError ) as e :
605+ swrite (FLAG_HEAD_EXCEPT )
606+ swrite ("Server error - %s: %s" % (e .__class__ .__name__ ,str (e )))
607+ swrite (FLAG_TAIL_EXCEPT )
608+ refresh = True
609+ continue
610+ except requests .exceptions .SSLError as e :
611+ # Give SSL recommendations
612+ swrite (FLAG_HEAD_EXCEPT )
613+ swrite ("SSL error: %s" % e )
614+ swrite ("\n If you trust the remote server, you can work "
615+ "around this error with `--nosslverify`" )
616+ swrite (FLAG_TAIL_EXCEPT )
617+ refresh = True
618+ continue
619+ except (socket .error ,
620+ requests .exceptions .HTTPError ,
621+ requests .exceptions .ConnectionError ,
622+ requests .exceptions .InvalidURL ,
623+ xmlrpc .client .ProtocolError ) as e :
624+ swrite (FLAG_HEAD_EXCEPT )
625+ swrite ("Connection lost/failed - %s: %s" % (e .__class__ .__name__ ,str (e )))
626+ swrite (FLAG_TAIL_EXCEPT )
627+ refresh = True
628+ continue
581629
582630def main (unittest_bz_instance = None ):
631+ """ (Patched version)
632+ """
583633 try :
584- try :
585- return _main (unittest_bz_instance )
586- except (Exception , KeyboardInterrupt ):
587- log .debug ("" , exc_info = True )
588- raise
634+ _main (unittest_bz_instance )
589635 except KeyboardInterrupt :
590- print ("\n Exited at user request." )
591- sys .exit (1 )
592- except (xmlrpc .client .Fault , bugzilla .BugzillaError ) as e :
593- print ("\n Server error: %s" % str (e ))
594- sys .exit (3 )
595- except requests .exceptions .SSLError as e :
596- # Give SSL recommendations
597- print ("SSL error: %s" % e )
598- print ("\n If you trust the remote server, you can work "
599- "around this error with:\n "
600- " bugzilla --nosslverify ..." )
601- sys .exit (4 )
602- except (socket .error ,
603- requests .exceptions .HTTPError ,
604- requests .exceptions .ConnectionError ,
605- requests .exceptions .InvalidURL ,
606- xmlrpc .client .ProtocolError ) as e :
607- print ("\n Connection lost/failed: %s" % str (e ))
608- sys .exit (2 )
636+ swrite (FLAG_HEAD_STRING )
637+ swrite ("Exited at user request" )
638+ swrite (FLAG_HEAD_STRING )
639+ sflush ()
640+ sys .exit (0 )
641+ except BaseException :
642+ log .debug ("" , exc_info = True )
643+ raise
609644
610645
611646def mi ():
612- main ()
647+ main ()
0 commit comments