2278
+ − 1 #!/usr/bin/env python2
+ − 2 # -*- coding: utf-8 -*-
+ − 3
+ − 4 # jp: a SàT command line tool
+ − 5 # Copyright (C) 2009-2016 Jérôme Poisson (goffi@goffi.org)
+ − 6
+ − 7 # This program is free software: you can redistribute it and/or modify
+ − 8 # it under the terms of the GNU Affero General Public License as published by
+ − 9 # the Free Software Foundation, either version 3 of the License, or
+ − 10 # (at your option) any later version.
+ − 11
+ − 12 # This program is distributed in the hope that it will be useful,
+ − 13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
+ − 14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ − 15 # GNU Affero General Public License for more details.
+ − 16
+ − 17 # You should have received a copy of the GNU Affero General Public License
+ − 18 # along with this program. If not, see <http://www.gnu.org/licenses/>.
+ − 19
+ − 20
+ − 21 import base
+ − 22 from sat.core.i18n import _
+ − 23 from sat_frontends.jp.constants import Const as C
+ − 24 from sat.tools.common.ansi import ANSI as A
+ − 25 import subprocess
+ − 26 import argparse
+ − 27 import os
+ − 28 import sys
+ − 29
+ − 30 __commands__ = [ "Input" ]
+ − 31 OPT_STDIN = 'stdin'
+ − 32 OPT_SHORT = 'short'
+ − 33 OPT_LONG = 'long'
+ − 34 OPT_POS = 'positional'
+ − 35 OPT_IGNORE = 'ignore'
+ − 36 OPT_TYPES = ( OPT_STDIN , OPT_SHORT , OPT_LONG , OPT_POS , OPT_IGNORE )
+ − 37
+ − 38
+ − 39 class InputCommon ( base . CommandBase ):
+ − 40
+ − 41 def __init__ ( self , host , name , help ):
+ − 42 base . CommandBase . __init__ ( self , host , name , use_verbose = True , use_profile = False , help = help )
+ − 43 self . idx = 0
+ − 44 self . reset ()
+ − 45
+ − 46 def reset ( self ):
+ − 47 self . args_idx = 0
+ − 48 self . _stdin = []
+ − 49 self . _opts = []
+ − 50 self . _pos = []
+ − 51
+ − 52 def add_parser_options ( self ):
+ − 53 self . parser . add_argument ( "--encoding" , default = 'utf-8' , help = _ ( u "encoding of the input data" ))
+ − 54 self . parser . add_argument ( "-i" , "--stdin" , action = 'append_const' , const = ( OPT_STDIN , None ), dest = 'arguments' , help = _ ( u "standard input" ))
+ − 55 self . parser . add_argument ( "-s" , "--short" , type = self . opt ( OPT_SHORT ), action = 'append' , dest = 'arguments' , help = _ ( u "short option" ))
+ − 56 self . parser . add_argument ( "-l" , "--long" , type = self . opt ( OPT_LONG ), action = 'append' , dest = 'arguments' , help = _ ( u "long option" ))
+ − 57 self . parser . add_argument ( "-p" , "--positional" , type = self . opt ( OPT_POS ), action = 'append' , dest = 'arguments' , help = _ ( u "positional argument" ))
+ − 58 self . parser . add_argument ( "-x" , "--ignore" , action = 'append_const' , const = ( OPT_IGNORE , None ), dest = 'arguments' , help = _ ( u "ignore value" ))
+ − 59 self . parser . add_argument ( "-D" , "--debug" , action = 'store_true' , help = _ ( u "don't actually run commands but echo what would be launched" ))
+ − 60 self . parser . add_argument ( "command" , nargs = argparse . REMAINDER )
+ − 61
+ − 62 def opt ( self , type_ ):
+ − 63 return lambda s : ( type_ , s )
+ − 64
+ − 65 def addValue ( self , value ):
+ − 66 """add a parsed value according to arguments sequence"""
+ − 67 arguments = self . args . arguments
+ − 68 try :
+ − 69 arg_type , arg_name = arguments [ self . args_idx ]
+ − 70 except IndexError :
+ − 71 self . disp ( _ ( u "arguments in input data and in arguments sequence don't match" ), error = True )
+ − 72 self . host . quit ( C . EXIT_DATA_ERROR )
+ − 73 self . args_idx += 1
+ − 74 while self . args_idx < len ( arguments ):
+ − 75 next_arg = arguments [ self . args_idx ]
+ − 76 if next_arg [ 0 ] not in OPT_TYPES :
+ − 77 # we have a filter
+ − 78 filter_type , filter_arg = arguments [ self . args_idx ]
+ − 79 value = self . filter ( filter_type , filter_arg , value )
+ − 80 else :
+ − 81 break
+ − 82 self . args_idx += 1
+ − 83
+ − 84 if not isinstance ( value , list ):
+ − 85 value = [ value ]
+ − 86
+ − 87 for v in value :
+ − 88 if arg_type == OPT_STDIN :
+ − 89 self . _stdin . append ( v . encode ( 'utf-8' ))
+ − 90 elif arg_type == OPT_SHORT :
+ − 91 self . _opts . append ( '- {} ' . format ( arg_name ))
+ − 92 self . _opts . append ( v . encode ( 'utf-8' ))
+ − 93 elif arg_type == OPT_LONG :
+ − 94 self . _opts . append ( '-- {} ' . format ( arg_name ))
+ − 95 self . _opts . append ( v . encode ( 'utf-8' ))
+ − 96 elif arg_type == OPT_POS :
+ − 97 self . _pos . append ( v . encode ( 'utf-8' ))
+ − 98 elif arg_type == OPT_IGNORE :
+ − 99 pass
+ − 100 else :
+ − 101 self . parser . error ( _ ( u "Invalid argument, an option type is expected, got {type_} : {name} " ) . format (
+ − 102 type_ = arg_type , name = arg_name ))
+ − 103
+ − 104 def runCommand ( self ):
+ − 105 """run requested command with parsed arguments"""
+ − 106 if self . args_idx != len ( self . args . arguments ):
+ − 107 self . disp ( _ ( u "arguments in input data and in arguments sequence don't match" ), error = True )
+ − 108 self . host . quit ( C . EXIT_DATA_ERROR )
+ − 109 stdin = '' . join ( self . _stdin )
+ − 110 if self . args . debug :
+ − 111 self . disp ( _ ( u 'command {idx} ' ) . format ( idx = self . idx ))
+ − 112 if stdin :
+ − 113 self . disp ( u '--- STDIN ---' )
+ − 114 self . disp ( stdin . decode ( 'utf-8' ))
+ − 115 self . disp ( u '-------------' )
+ − 116 self . disp ( u ' {indent}{prog} {static} {options} {positionals} ' . format (
+ − 117 indent = 4 * u ' ' ,
+ − 118 prog = sys . argv [ 0 ],
+ − 119 static = ' ' . join ( self . args . command ) . encode ( 'utf-8' ),
+ − 120 options = u ' ' . join ([ o . encode ( 'utf-8' ) for o in self . _opts ]),
+ − 121 positionals = u ' ' . join ([ p . encode ( 'utf-8' ) for p in self . _pos ])
+ − 122 ))
+ − 123 self . disp ( u '' )
+ − 124 else :
+ − 125 self . disp ( _ ( u 'command {idx} ' ) . format ( idx = self . idx ), no_lf = True )
+ − 126 with open ( os . devnull , 'wb' ) as DEVNULL :
+ − 127 p = subprocess . Popen ([ sys . argv [ 0 ]] + self . args . command + self . _opts + self . _pos ,
+ − 128 stdin = subprocess . PIPE , stdout = DEVNULL , stderr = DEVNULL )
+ − 129 p . communicate ( stdin )
+ − 130 ret = p . wait ()
+ − 131 if ret == 0 :
+ − 132 self . disp ( A . color ( C . A_SUCCESS , _ ( u 'OK' )))
+ − 133 else :
+ − 134 self . disp ( A . color ( C . A_FAILURE , _ ( u 'FAILED' )))
+ − 135
+ − 136 self . reset ()
+ − 137 self . idx += 1
+ − 138
+ − 139 def filter ( self , filter_type , filter_arg , value ):
+ − 140 raise NotImplementedError
+ − 141
+ − 142
+ − 143 class Csv ( InputCommon ):
+ − 144
+ − 145 def __init__ ( self , host ):
+ − 146 super ( Csv , self ) . __init__ ( host , 'csv' , _ ( u 'comma-separated values' ))
+ − 147
+ − 148 def add_parser_options ( self ):
+ − 149 InputCommon . add_parser_options ( self )
+ − 150 self . parser . add_argument ( "-r" , "--row" , type = int , default = 0 , help = _ ( u "starting row (previous ones will be ignored)" ))
+ − 151 self . parser . add_argument ( "-S" , "--split" , action = 'append_const' , const = ( 'split' , None ), dest = 'arguments' , help = _ ( u "split value in several options" ))
+ − 152
+ − 153 def filter ( self , arg_type , filter_type , filter_arg , value ):
+ − 154 if filter_type == 'split' :
+ − 155 return value . split ()
+ − 156
+ − 157 super ( Csv , self ) . filter ( filter_type , filter_arg , value )
+ − 158
+ − 159 def start ( self ):
+ − 160 import csv
+ − 161 reader = csv . reader ( sys . stdin )
+ − 162 for idx , row in enumerate ( reader ):
+ − 163 if idx < self . args . row :
+ − 164 continue
+ − 165 for value in row :
+ − 166 self . addValue ( value . decode ( self . args . encoding ))
+ − 167 self . runCommand ()
+ − 168
+ − 169
+ − 170 class Input ( base . CommandBase ):
+ − 171 subcommands = ( Csv ,)
+ − 172
+ − 173 def __init__ ( self , host ):
+ − 174 super ( Input , self ) . __init__ ( host , 'input' , use_profile = False , help = _ ( u 'launch command with external input' ))