Skip to content

Commit

Permalink
Refactor python cssbeautifier to reuse jsbeautifier CLI methods
Browse files Browse the repository at this point in the history
This change also adds smoke tests for installed cssbeautifier
package.
  • Loading branch information
bitwiseman committed Aug 20, 2020
1 parent d763fe1 commit 90b6e55
Show file tree
Hide file tree
Showing 8 changed files with 305 additions and 243 deletions.
13 changes: 9 additions & 4 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -81,16 +81,18 @@ js/lib/*.js: $(BUILD_DIR)/node $(BUILD_DIR)/generate $(wildcard js/src/*) $(wild
# python package generation
python/dist/*: $(BUILD_DIR)/python $(wildcard python/**/*.py) python/jsbeautifier/* python/cssbeautifier/*
@echo Building python package...
rm -f python/dist/*
@rm -f python/dist/*
@cd python && \
cp setup-js.py setup.py && \
cp setup-css.py setup.py && \
$(PYTHON) setup.py sdist && \
rm setup.py
@cd python && \
cp setup-css.py setup.py && \
cp setup-js.py setup.py && \
$(PYTHON) setup.py sdist && \
rm setup.py
$(SCRIPT_DIR)/python-rel pip install -U python/dist/*
# Order matters here! Install css then js to make sure the local dist version of js is used
$(SCRIPT_DIR)/python-rel pip install -U python/dist/cssbeautifier*
$(SCRIPT_DIR)/python-rel pip install -U python/dist/jsbeautifier*

# python package generation
build/*.tgz: js/lib/*.js
Expand Down Expand Up @@ -129,6 +131,9 @@ $(BUILD_DIR)/node: package.json package-lock.json | $(BUILD_DIR)

$(BUILD_DIR)/python: python/setup-js.py python/setup-css.py | $(BUILD_DIR) $(BUILD_DIR)/virtualenv
@$(PYTHON) --version
# Order matters here! Install css then js to make sure the local dist version of js is used
@cp ./python/setup-css.py ./python/setup.py
$(SCRIPT_DIR)/python-dev pip install -e ./python
@cp ./python/setup-js.py ./python/setup.py
$(SCRIPT_DIR)/python-dev pip install -e ./python
@rm ./python/setup.py
Expand Down
87 changes: 33 additions & 54 deletions python/cssbeautifier/_main.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
import copy
import getopt
from cssbeautifier.__version__ import __version__
from jsbeautifier import isFileDifferent, mkdir_p
from jsbeautifier.cli import *
from cssbeautifier.css.options import BeautifierOptions
from cssbeautifier.css.beautifier import Beautifier

Expand All @@ -48,22 +48,7 @@ def beautify(string, opts=None):


def beautify_file(file_name, opts=None):
if file_name == "-": # stdin
try:
if sys.stdin.isatty():
raise Exception()

stream = sys.stdin
except Exception:
print("Must pipe input or define input file.\n", file=sys.stderr)
usage(sys.stderr)
raise Exception()
else:
stream = open(file_name)

content = "".join(stream.readlines())
b = Beautifier(content, opts)
return b.beautify()
return process_file(file_name, opts, beautify)


def usage(stream=sys.stdout):
Expand Down Expand Up @@ -125,6 +110,7 @@ def main():
argv,
"hvio:rs:c:e:tnb:",
[
"editorconfig",
"help",
"usage",
"version",
Expand All @@ -150,11 +136,11 @@ def main():

css_options = default_options()

file = None
outfile = "stdout"
filepath_params = []
filepath_params.extend(args)

outfile_param = "stdout"
replace = False
if len(args) == 1:
file = args[0]

for opt, arg in opts:
if opt in ("--stdin", "-i"):
Expand Down Expand Up @@ -190,41 +176,34 @@ def main():
css_options.space_around_combinator = True
elif opt in ("--indent-empty-lines"):
css_options.indent_empty_lines = True

if not file:
file = "-"
elif opt in ("--editorconfig"):
css_options.editorconfig = True

try:
if outfile == "stdout" and replace and not file == "-":
outfile = file

pretty = beautify_file(file, css_options)

if outfile == "stdout":
# python automatically converts newlines in text to "\r\n" when on windows
# switch to binary to prevent this
if sys.platform == "win32":
import msvcrt

msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY)

sys.stdout.write(pretty)
else:
if isFileDifferent(outfile, pretty):
mkdir_p(os.path.dirname(outfile))

# python automatically converts newlines in text to "\r\n" when on windows
# set newline to empty to prevent this
with io.open(outfile, "wt", newline="") as f:
print("writing " + outfile, file=sys.stderr)
try:
f.write(pretty)
except TypeError:
# This is not pretty, but given how we did the version import
# it is the only way to do this without having setup.py
# fail on a missing six dependency.
six = __import__("six")
f.write(six.u(pretty))
filepaths, replace = get_filepaths_from_params(filepath_params, replace)
for filepath in filepaths:
if not replace:
outfile = outfile_param
else:
outfile = filepath

css_options = integrate_editorconfig_options(
filepath, css_options, outfile, "js"
)

pretty = beautify_file(filepath, css_options)

write_beautified_output(pretty, css_options, outfile)

except MissingInputStreamError:
print("Must pipe input or define at least one file.\n", file=sys.stderr)
usage(sys.stderr)
return 1

except UnicodeError as ex:
print("Error while decoding input or encoding output:", file=sys.stderr)
print(ex, file=sys.stderr)
return 1

except Exception as ex:
print(ex, file=sys.stderr)
Expand Down
196 changes: 14 additions & 182 deletions python/jsbeautifier/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import copy
import glob
from jsbeautifier.__version__ import __version__
from jsbeautifier.cli import *
from jsbeautifier.javascript.options import BeautifierOptions
from jsbeautifier.javascript.beautifier import Beautifier

Expand Down Expand Up @@ -63,9 +64,13 @@
#
# Here are the available options: (read source)


class MissingInputStreamError(Exception):
pass
__all__ = [
"default_options",
"beautify",
"beautify_file",
"usage",
"main",
]


def default_options():
Expand All @@ -77,75 +82,8 @@ def beautify(string, opts=default_options()):
return b.beautify(string, opts)


def set_file_editorconfig_opts(filename, js_options):
from editorconfig import get_properties, EditorConfigError

try:
_ecoptions = get_properties(os.path.abspath(filename))

if _ecoptions.get("indent_style") == "tab":
js_options.indent_with_tabs = True
elif _ecoptions.get("indent_style") == "space":
js_options.indent_with_tabs = False

if _ecoptions.get("indent_size"):
js_options.indent_size = int(_ecoptions["indent_size"])

if _ecoptions.get("max_line_length"):
if _ecoptions.get("max_line_length") == "off":
js_options.wrap_line_length = 0
else:
js_options.wrap_line_length = int(_ecoptions["max_line_length"])

if _ecoptions.get("insert_final_newline") == "true":
js_options.end_with_newline = True
elif _ecoptions.get("insert_final_newline") == "false":
js_options.end_with_newline = False

if _ecoptions.get("end_of_line"):
if _ecoptions["end_of_line"] == "cr":
js_options.eol = "\r"
elif _ecoptions["end_of_line"] == "lf":
js_options.eol = "\n"
elif _ecoptions["end_of_line"] == "crlf":
js_options.eol = "\r\n"

except EditorConfigError:
# do not error on bad editor config
print("Error loading EditorConfig. Ignoring.", file=sys.stderr)


def beautify_file(file_name, opts=default_options()):
input_string = ""
if file_name == "-": # stdin
if sys.stdin.isatty():
raise MissingInputStreamError()

stream = sys.stdin
if platform.platform().lower().startswith("windows"):
if sys.version_info.major >= 3:
# for python 3 on windows this prevents conversion
stream = io.TextIOWrapper(sys.stdin.buffer, newline="")
elif platform.architecture()[0] == "32bit":
# for python 2 x86 on windows this prevents conversion
import msvcrt

msvcrt.setmode(sys.stdin.fileno(), os.O_BINARY)
else:
raise Exception(
"Pipe to stdin not supported on Windows with Python 2.x 64-bit."
)

input_string = stream.read()

# if you pipe an empty string, that is a failure
if input_string == "":
raise MissingInputStreamError()
else:
stream = io.open(file_name, "rt", newline="", encoding="UTF-8")
input_string = stream.read()

return beautify(input_string, opts)
return process_file(file_name, opts, beautify)


def usage(stream=sys.stdout):
Expand Down Expand Up @@ -217,24 +155,6 @@ def usage(stream=sys.stdout):
return 0


def mkdir_p(path):
try:
if path:
os.makedirs(path)
except OSError as exc: # Python >2.5
if exc.errno == errno.EEXIST and os.path.isdir(path):
pass
else:
raise Exception()


def isFileDifferent(filepath, expected):
try:
return "".join(io.open(filepath, "rt", newline="").readlines()) != expected
except BaseException:
return True


def main():

argv = sys.argv[1:]
Expand Down Expand Up @@ -357,108 +277,20 @@ def main():
return usage()

try:
filepaths = []
if not filepath_params or (
len(filepath_params) == 1 and filepath_params[0] == "-"
):
# default to stdin
filepath_params = []
filepaths.append("-")

for filepath_param in filepath_params:
# ignore stdin setting if files are specified
if "-" == filepath_param:
continue

# Check if each literal filepath exists
if os.path.isfile(filepath_param):
filepaths.append(filepath_param)
elif "*" in filepath_param or "?" in filepath_param:
# handle globs
# empty result is okay
if sys.version_info.major == 2 or (
sys.version_info.major == 3 and sys.version_info.minor <= 4
):
if "**" in filepath_param:
raise Exception(
"Recursive globs not supported on Python <= 3.4."
)
filepaths.extend(glob.glob(filepath_param))
else:
filepaths.extend(glob.glob(filepath_param, recursive=True))
else:
# not a glob and not a file
raise OSError(errno.ENOENT, os.strerror(errno.ENOENT), filepath_param)

if len(filepaths) > 1:
replace = True
elif filepaths and filepaths[0] == "-":
replace = False

# remove duplicates
filepaths = set(filepaths)

filepaths, replace = get_filepaths_from_params(filepath_params, replace)
for filepath in filepaths:
if not replace:
outfile = outfile_param
else:
outfile = filepath

# Editorconfig used only on files, not stdin
if getattr(js_options, "editorconfig"):
editorconfig_filepath = filepath

if editorconfig_filepath == "-":
if outfile != "stdout":
editorconfig_filepath = outfile
else:
fileType = "js"
editorconfig_filepath = "stdin." + fileType

# debug("EditorConfig is enabled for ", editorconfig_filepath);
js_options = copy.copy(js_options)
set_file_editorconfig_opts(editorconfig_filepath, js_options)
js_options = integrate_editorconfig_options(
filepath, js_options, outfile, "js"
)

pretty = beautify_file(filepath, js_options)

if outfile == "stdout":
stream = sys.stdout

# python automatically converts newlines in text to "\r\n" when on windows
# switch to binary to prevent this
if platform.platform().lower().startswith("windows"):
if sys.version_info.major >= 3:
# for python 3 on windows this prevents conversion
stream = io.TextIOWrapper(sys.stdout.buffer, newline="")
elif platform.architecture()[0] == "32bit":
# for python 2 x86 on windows this prevents conversion
import msvcrt

msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY)
else:
raise Exception(
"Pipe to stdout not supported on Windows with Python 2.x 64-bit."
)

stream.write(pretty)
else:
if isFileDifferent(outfile, pretty):
mkdir_p(os.path.dirname(outfile))

# python automatically converts newlines in text to "\r\n" when on windows
# set newline to empty to prevent this
with io.open(outfile, "wt", newline="", encoding="UTF-8") as f:
print("beautified " + outfile, file=sys.stdout)
try:
f.write(pretty)
except TypeError:
# This is not pretty, but given how we did the version import
# it is the only way to do this without having setup.py
# fail on a missing six dependency.
six = __import__("six")
f.write(six.u(pretty))
elif not js_options.keep_quiet:
print("beautified " + outfile + " - unchanged", file=sys.stdout)
write_beautified_output(pretty, js_options, outfile)

except MissingInputStreamError:
print("Must pipe input or define at least one file.\n", file=sys.stderr)
Expand Down
Loading

0 comments on commit 90b6e55

Please sign in to comment.