codekingpro/portable-devtools
114k
1#!/usr/bin/env python2#3# Copyright (C) 2009-2020 the sqlparse authors and contributors4# <see AUTHORS file>5#6# This module is part of python-sqlparse and is released under7# the BSD License: https://opensource.org/licenses/BSD-3-Clause8 9"""Module that contains the command line app.10 11Why does this file exist, and why not put this in __main__?12 You might be tempted to import things from __main__ later, but that will13 cause problems: the code will get executed twice:14 - When you run `python -m sqlparse` python will execute15 ``__main__.py`` as a script. That means there won't be any16 ``sqlparse.__main__`` in ``sys.modules``.17 - When you import __main__ it will get executed again (as a module) because18 there's no ``sqlparse.__main__`` in ``sys.modules``.19 Also see (1) from http://click.pocoo.org/5/setuptools/#setuptools-integration20"""21 22import argparse23import sys24from io import TextIOWrapper25 26import sqlparse27from sqlparse.exceptions import SQLParseError28 29 30# TODO: Add CLI Tests31# TODO: Simplify formatter by using argparse `type` arguments32def create_parser():33 _CASE_CHOICES = ['upper', 'lower', 'capitalize']34 35 parser = argparse.ArgumentParser(36 prog='sqlformat',37 description='Format FILE according to OPTIONS. Use "-" as FILE '38 'to read from stdin.',39 usage='%(prog)s [OPTIONS] FILE, ...',40 )41 42 parser.add_argument('filename')43 44 parser.add_argument(45 '-o', '--outfile',46 dest='outfile',47 metavar='FILE',48 help='write output to FILE (defaults to stdout)')49 50 parser.add_argument(51 '--version',52 action='version',53 version=sqlparse.__version__)54 55 group = parser.add_argument_group('Formatting Options')56 57 group.add_argument(58 '-k', '--keywords',59 metavar='CHOICE',60 dest='keyword_case',61 choices=_CASE_CHOICES,62 help='change case of keywords, CHOICE is one of {}'.format(63 ', '.join('"{}"'.format(x) for x in _CASE_CHOICES)))64 65 group.add_argument(66 '-i', '--identifiers',67 metavar='CHOICE',68 dest='identifier_case',69 choices=_CASE_CHOICES,70 help='change case of identifiers, CHOICE is one of {}'.format(71 ', '.join('"{}"'.format(x) for x in _CASE_CHOICES)))72 73 group.add_argument(74 '-l', '--language',75 metavar='LANG',76 dest='output_format',77 choices=['python', 'php'],78 help='output a snippet in programming language LANG, '79 'choices are "python", "php"')80 81 group.add_argument(82 '--strip-comments',83 dest='strip_comments',84 action='store_true',85 default=False,86 help='remove comments')87 88 group.add_argument(89 '-r', '--reindent',90 dest='reindent',91 action='store_true',92 default=False,93 help='reindent statements')94 95 group.add_argument(96 '--indent_width',97 dest='indent_width',98 default=2,99 type=int,100 help='indentation width (defaults to 2 spaces)')101 102 group.add_argument(103 '--indent_after_first',104 dest='indent_after_first',105 action='store_true',106 default=False,107 help='indent after first line of statement (e.g. SELECT)')108 109 group.add_argument(110 '--indent_columns',111 dest='indent_columns',112 action='store_true',113 default=False,114 help='indent all columns by indent_width instead of keyword length')115 116 group.add_argument(117 '-a', '--reindent_aligned',118 action='store_true',119 default=False,120 help='reindent statements to aligned format')121 122 group.add_argument(123 '-s', '--use_space_around_operators',124 action='store_true',125 default=False,126 help='place spaces around mathematical operators')127 128 group.add_argument(129 '--wrap_after',130 dest='wrap_after',131 default=0,132 type=int,133 help='Column after which lists should be wrapped')134 135 group.add_argument(136 '--comma_first',137 dest='comma_first',138 default=False,139 type=bool,140 help='Insert linebreak before comma (default False)')141 142 group.add_argument(143 '--encoding',144 dest='encoding',145 default='utf-8',146 help='Specify the input encoding (default utf-8)')147 148 return parser149 150 151def _error(msg):152 """Print msg and optionally exit with return code exit_."""153 sys.stderr.write('[ERROR] {}\n'.format(msg))154 return 1155 156 157def main(args=None):158 parser = create_parser()159 args = parser.parse_args(args)160 161 if args.filename == '-': # read from stdin162 wrapper = TextIOWrapper(sys.stdin.buffer, encoding=args.encoding)163 try:164 data = wrapper.read()165 finally:166 wrapper.detach()167 else:168 try:169 with open(args.filename, encoding=args.encoding) as f:170 data = ''.join(f.readlines())171 except OSError as e:172 return _error(173 'Failed to read {}: {}'.format(args.filename, e))174 175 close_stream = False176 if args.outfile:177 try:178 stream = open(args.outfile, 'w', encoding=args.encoding)179 close_stream = True180 except OSError as e:181 return _error('Failed to open {}: {}'.format(args.outfile, e))182 else:183 stream = sys.stdout184 185 formatter_opts = vars(args)186 try:187 formatter_opts = sqlparse.formatter.validate_options(formatter_opts)188 except SQLParseError as e:189 return _error('Invalid options: {}'.format(e))190 191 s = sqlparse.format(data, **formatter_opts)192 stream.write(s)193 stream.flush()194 if close_stream:195 stream.close()196 return 0197 