123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196 |
- #!/usr/bin/env python
- #
- # Copyright (C) 2009-2020 the sqlparse authors and contributors
- # <see AUTHORS file>
- #
- # This module is part of python-sqlparse and is released under
- # the BSD License: https://opensource.org/licenses/BSD-3-Clause
- """Module that contains the command line app.
- Why does this file exist, and why not put this in __main__?
- You might be tempted to import things from __main__ later, but that will
- cause problems: the code will get executed twice:
- - When you run `python -m sqlparse` python will execute
- ``__main__.py`` as a script. That means there won't be any
- ``sqlparse.__main__`` in ``sys.modules``.
- - When you import __main__ it will get executed again (as a module) because
- there's no ``sqlparse.__main__`` in ``sys.modules``.
- Also see (1) from http://click.pocoo.org/5/setuptools/#setuptools-integration
- """
- import argparse
- import sys
- from io import TextIOWrapper
- import sqlparse
- from sqlparse.exceptions import SQLParseError
- # TODO: Add CLI Tests
- # TODO: Simplify formatter by using argparse `type` arguments
- def create_parser():
- _CASE_CHOICES = ['upper', 'lower', 'capitalize']
- parser = argparse.ArgumentParser(
- prog='sqlformat',
- description='Format FILE according to OPTIONS. Use "-" as FILE '
- 'to read from stdin.',
- usage='%(prog)s [OPTIONS] FILE, ...',
- )
- parser.add_argument('filename')
- parser.add_argument(
- '-o', '--outfile',
- dest='outfile',
- metavar='FILE',
- help='write output to FILE (defaults to stdout)')
- parser.add_argument(
- '--version',
- action='version',
- version=sqlparse.__version__)
- group = parser.add_argument_group('Formatting Options')
- group.add_argument(
- '-k', '--keywords',
- metavar='CHOICE',
- dest='keyword_case',
- choices=_CASE_CHOICES,
- help='change case of keywords, CHOICE is one of {}'.format(
- ', '.join('"{}"'.format(x) for x in _CASE_CHOICES)))
- group.add_argument(
- '-i', '--identifiers',
- metavar='CHOICE',
- dest='identifier_case',
- choices=_CASE_CHOICES,
- help='change case of identifiers, CHOICE is one of {}'.format(
- ', '.join('"{}"'.format(x) for x in _CASE_CHOICES)))
- group.add_argument(
- '-l', '--language',
- metavar='LANG',
- dest='output_format',
- choices=['python', 'php'],
- help='output a snippet in programming language LANG, '
- 'choices are "python", "php"')
- group.add_argument(
- '--strip-comments',
- dest='strip_comments',
- action='store_true',
- default=False,
- help='remove comments')
- group.add_argument(
- '-r', '--reindent',
- dest='reindent',
- action='store_true',
- default=False,
- help='reindent statements')
- group.add_argument(
- '--indent_width',
- dest='indent_width',
- default=2,
- type=int,
- help='indentation width (defaults to 2 spaces)')
- group.add_argument(
- '--indent_after_first',
- dest='indent_after_first',
- action='store_true',
- default=False,
- help='indent after first line of statement (e.g. SELECT)')
- group.add_argument(
- '--indent_columns',
- dest='indent_columns',
- action='store_true',
- default=False,
- help='indent all columns by indent_width instead of keyword length')
- group.add_argument(
- '-a', '--reindent_aligned',
- action='store_true',
- default=False,
- help='reindent statements to aligned format')
- group.add_argument(
- '-s', '--use_space_around_operators',
- action='store_true',
- default=False,
- help='place spaces around mathematical operators')
- group.add_argument(
- '--wrap_after',
- dest='wrap_after',
- default=0,
- type=int,
- help='Column after which lists should be wrapped')
- group.add_argument(
- '--comma_first',
- dest='comma_first',
- default=False,
- type=bool,
- help='Insert linebreak before comma (default False)')
- group.add_argument(
- '--encoding',
- dest='encoding',
- default='utf-8',
- help='Specify the input encoding (default utf-8)')
- return parser
- def _error(msg):
- """Print msg and optionally exit with return code exit_."""
- sys.stderr.write('[ERROR] {}\n'.format(msg))
- return 1
- def main(args=None):
- parser = create_parser()
- args = parser.parse_args(args)
- if args.filename == '-': # read from stdin
- wrapper = TextIOWrapper(sys.stdin.buffer, encoding=args.encoding)
- try:
- data = wrapper.read()
- finally:
- wrapper.detach()
- else:
- try:
- with open(args.filename, encoding=args.encoding) as f:
- data = ''.join(f.readlines())
- except OSError as e:
- return _error(
- 'Failed to read {}: {}'.format(args.filename, e))
- close_stream = False
- if args.outfile:
- try:
- stream = open(args.outfile, 'w', encoding=args.encoding)
- close_stream = True
- except OSError as e:
- return _error('Failed to open {}: {}'.format(args.outfile, e))
- else:
- stream = sys.stdout
- formatter_opts = vars(args)
- try:
- formatter_opts = sqlparse.formatter.validate_options(formatter_opts)
- except SQLParseError as e:
- return _error('Invalid options: {}'.format(e))
- s = sqlparse.format(data, **formatter_opts)
- stream.write(s)
- stream.flush()
- if close_stream:
- stream.close()
- return 0
|