hercule.py
branchtls-sprint
changeset 1802 d628defebc17
parent 1141 66d532e62dd8
child 1977 606923dff11b
equal deleted inserted replaced
1801:672acc730ce5 1802:d628defebc17
    11 
    11 
    12 from logilab.common import flatten
    12 from logilab.common import flatten
    13 from logilab.common.cli import CLIHelper
    13 from logilab.common.cli import CLIHelper
    14 from logilab.common.clcommands import BadCommandUsage, pop_arg, register_commands
    14 from logilab.common.clcommands import BadCommandUsage, pop_arg, register_commands
    15 from cubicweb.toolsutils import CONNECT_OPTIONS, Command
    15 from cubicweb.toolsutils import CONNECT_OPTIONS, Command
    16  
    16 
    17 # result formatter ############################################################
    17 # result formatter ############################################################
    18 
    18 
    19 PAGER = os.environ.get('PAGER', 'less')
    19 PAGER = os.environ.get('PAGER', 'less')
    20             
    20 
    21 def pager_format_results(writer, layout):
    21 def pager_format_results(writer, layout):
    22     """pipe results to a pager like more or less"""
    22     """pipe results to a pager like more or less"""
    23     (r, w) = os.pipe()
    23     (r, w) = os.pipe()
    24     pid = os.fork()
    24     pid = os.fork()
    25     if pid == 0:
    25     if pid == 0:
    40         os.waitpid(pid, 0)
    40         os.waitpid(pid, 0)
    41 
    41 
    42 def izip2(list1, list2):
    42 def izip2(list1, list2):
    43     for i in xrange(len(list1)):
    43     for i in xrange(len(list1)):
    44         yield list1[i] + tuple(list2[i])
    44         yield list1[i] + tuple(list2[i])
    45         
    45 
    46 def format_results(writer, layout, stream=sys.stdout): 
    46 def format_results(writer, layout, stream=sys.stdout):
    47     """format result as text into the given file like object"""
    47     """format result as text into the given file like object"""
    48     writer.format(layout, stream)
    48     writer.format(layout, stream)
    49 
    49 
    50 
    50 
    51 try:
    51 try:
    58     if isinstance(value, unicode):
    58     if isinstance(value, unicode):
    59         return value.encode(encoding, 'replace')
    59         return value.encode(encoding, 'replace')
    60     return str(value)
    60     return str(value)
    61 
    61 
    62 # command line querier ########################################################
    62 # command line querier ########################################################
    63     
    63 
    64 class RQLCli(CLIHelper):
    64 class RQLCli(CLIHelper):
    65     """Interactive command line client for CubicWeb, allowing user to execute
    65     """Interactive command line client for CubicWeb, allowing user to execute
    66     arbitrary RQL queries and to fetch schema information
    66     arbitrary RQL queries and to fetch schema information
    67     """
    67     """
    68     # commands are prefixed by ":"
    68     # commands are prefixed by ":"
    72         'connect' :      "CubicWeb",
    72         'connect' :      "CubicWeb",
    73         'schema'  :      "CubicWeb",
    73         'schema'  :      "CubicWeb",
    74         'description'  : "CubicWeb",
    74         'description'  : "CubicWeb",
    75         'commit' :       "CubicWeb",
    75         'commit' :       "CubicWeb",
    76         'rollback' :     "CubicWeb",
    76         'rollback' :     "CubicWeb",
    77         'autocommit'  :  "Others", 
    77         'autocommit'  :  "Others",
    78         'debug' :        "Others",
    78         'debug' :        "Others",
    79         })
    79         })
    80     
    80 
    81     def __init__(self, application=None, user=None, password=None,
    81     def __init__(self, application=None, user=None, password=None,
    82                  host=None, debug=0):
    82                  host=None, debug=0):
    83         CLIHelper.__init__(self, os.path.join(os.environ["HOME"], ".erqlhist"))
    83         CLIHelper.__init__(self, os.path.join(os.environ["HOME"], ".erqlhist"))
    84         self.cnx = None
    84         self.cnx = None
    85         self.cursor = None
    85         self.cursor = None
    92         self._last_result = None
    92         self._last_result = None
    93         self._previous_lines = []
    93         self._previous_lines = []
    94         if application is not None:
    94         if application is not None:
    95             self.do_connect(application, user, password, host)
    95             self.do_connect(application, user, password, host)
    96         self.do_debug(debug)
    96         self.do_debug(debug)
    97         
    97 
    98     def do_connect(self, application, user=None, password=None, host=None):
    98     def do_connect(self, application, user=None, password=None, host=None):
    99         """connect to an cubicweb application"""
    99         """connect to an cubicweb application"""
   100         from cubicweb.dbapi import connect
   100         from cubicweb.dbapi import connect
   101         if user is None:
   101         if user is None:
   102             user = raw_input('login: ')
   102             user = raw_input('login: ')
   111         self.cursor = self.cnx.cursor()
   111         self.cursor = self.cnx.cursor()
   112         # add entities types to the completion commands
   112         # add entities types to the completion commands
   113         self._completer.list = (self.commands.keys() +
   113         self._completer.list = (self.commands.keys() +
   114                                 self.schema.entities() + ['Any'])
   114                                 self.schema.entities() + ['Any'])
   115         print _('You are now connected to %s') % application
   115         print _('You are now connected to %s') % application
   116         
   116 
   117 
   117 
   118     help_do_connect = ('connect', "connect <application> [<user> [<password> [<host>]]]",
   118     help_do_connect = ('connect', "connect <application> [<user> [<password> [<host>]]]",
   119                        _(do_connect.__doc__))
   119                        _(do_connect.__doc__))
   120 
   120 
   121     def do_debug(self, debug=1):
   121     def do_debug(self, debug=1):
   125             self._format = format_results
   125             self._format = format_results
   126         else:
   126         else:
   127             self._format = pager_format_results
   127             self._format = pager_format_results
   128         if self._debug:
   128         if self._debug:
   129             print _('Debug level set to %s'%debug)
   129             print _('Debug level set to %s'%debug)
   130         
   130 
   131     help_do_debug = ('debug', "debug [debug_level]", _(do_debug.__doc__))
   131     help_do_debug = ('debug', "debug [debug_level]", _(do_debug.__doc__))
   132     
   132 
   133     def do_description(self):
   133     def do_description(self):
   134         """display the description of the latest result"""
   134         """display the description of the latest result"""
   135         if self.rset.description is None:
   135         if self.rset.description is None:
   136             print _('No query has been executed')
   136             print _('No query has been executed')
   137         else:
   137         else:
   138             print '\n'.join([', '.join(line_desc)
   138             print '\n'.join([', '.join(line_desc)
   139                              for line_desc in self.rset.description])
   139                              for line_desc in self.rset.description])
   140 
   140 
   141     help_do_description = ('description', "description", _(do_description.__doc__))
   141     help_do_description = ('description', "description", _(do_description.__doc__))
   142     
   142 
   143     def do_schema(self, name=None):
   143     def do_schema(self, name=None):
   144         """display information about the application schema """
   144         """display information about the application schema """
   145         if self.cnx is None:
   145         if self.cnx is None:
   146             print _('You are not connected to an application !')
   146             print _('You are not connected to an application !')
   147             return
   147             return
   157             if self.schema.has_relation(name):
   157             if self.schema.has_relation(name):
   158                 self.display_schema(self.schema.rschema(name))
   158                 self.display_schema(self.schema.rschema(name))
   159                 done = 1
   159                 done = 1
   160         if done is None:
   160         if done is None:
   161             print _('Unable to find anything named "%s" in the schema !') % name
   161             print _('Unable to find anything named "%s" in the schema !') % name
   162             
   162 
   163     help_do_schema = ('schema', "schema [keyword]", _(do_schema.__doc__))
   163     help_do_schema = ('schema', "schema [keyword]", _(do_schema.__doc__))
   164 
   164 
   165     
   165 
   166     def do_commit(self):
   166     def do_commit(self):
   167         """commit the current transaction"""
   167         """commit the current transaction"""
   168         self.cnx.commit()
   168         self.cnx.commit()
   169 
   169 
   170     help_do_commit = ('commit', "commit", _(do_commit.__doc__))
   170     help_do_commit = ('commit', "commit", _(do_commit.__doc__))
   171     
   171 
   172     def do_rollback(self):
   172     def do_rollback(self):
   173         """rollback the current transaction"""
   173         """rollback the current transaction"""
   174         self.cnx.rollback()
   174         self.cnx.rollback()
   175 
   175 
   176     help_do_rollback = ('rollback', "rollback", _(do_rollback.__doc__))
   176     help_do_rollback = ('rollback', "rollback", _(do_rollback.__doc__))
   177     
   177 
   178     def do_autocommit(self):
   178     def do_autocommit(self):
   179         """toggle autocommit mode"""
   179         """toggle autocommit mode"""
   180         self.autocommit = not self.autocommit
   180         self.autocommit = not self.autocommit
   181 
   181 
   182     help_do_autocommit = ('autocommit', "autocommit", _(do_autocommit.__doc__))
   182     help_do_autocommit = ('autocommit', "autocommit", _(do_autocommit.__doc__))
   183     
   183 
   184 
   184 
   185     def handle_line(self, stripped_line):
   185     def handle_line(self, stripped_line):
   186         """handle non command line :
   186         """handle non command line :
   187         if the query is complete, executes it and displays results (if any)
   187         if the query is complete, executes it and displays results (if any)
   188         else, stores the query line and waits for the suite
   188         else, stores the query line and waits for the suite
   230 
   230 
   231 class CubicWebClientCommand(Command):
   231 class CubicWebClientCommand(Command):
   232     """A command line querier for CubicWeb, using the Relation Query Language.
   232     """A command line querier for CubicWeb, using the Relation Query Language.
   233 
   233 
   234     <application>
   234     <application>
   235       identifier of the application to connect to 
   235       identifier of the application to connect to
   236     """
   236     """
   237     name = 'client'
   237     name = 'client'
   238     arguments = '<application>'
   238     arguments = '<application>'
   239     options = CONNECT_OPTIONS + (
   239     options = CONNECT_OPTIONS + (
   240         ("verbose",
   240         ("verbose",
   245         ("batch",
   245         ("batch",
   246          {'short': 'b', 'type' : 'string', 'metavar': '<file>',
   246          {'short': 'b', 'type' : 'string', 'metavar': '<file>',
   247           'help': 'file containing a batch of RQL statements to execute.',
   247           'help': 'file containing a batch of RQL statements to execute.',
   248           }),
   248           }),
   249         )
   249         )
   250     
   250 
   251     def run(self, args):
   251     def run(self, args):
   252         """run the command with its specific arguments"""
   252         """run the command with its specific arguments"""
   253         appid = pop_arg(args, expected_size_after=None)
   253         appid = pop_arg(args, expected_size_after=None)
   254         batch_stream = None
   254         batch_stream = None
   255         if args:
   255         if args:
   269                     continue
   269                     continue
   270                 print '>>>', line
   270                 print '>>>', line
   271                 cli.handle_line(line)
   271                 cli.handle_line(line)
   272         else:
   272         else:
   273             cli.run()
   273             cli.run()
   274         
   274 
   275 register_commands((CubicWebClientCommand,))
   275 register_commands((CubicWebClientCommand,))