Archived
216 lines
5.7 KiB
Python
216 lines
5.7 KiB
Python
#!/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
|