chore!: Deprecate frappe.utils.minify
* Remove dead code from build.py * Whitespaces & imports style fixes
This commit is contained in:
parent
67df13f77f
commit
d72aeca18f
2 changed files with 15 additions and 346 deletions
149
frappe/build.py
149
frappe/build.py
|
|
@ -1,25 +1,21 @@
|
|||
# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and Contributors
|
||||
# Copyright (c) 2022, Frappe Technologies Pvt. Ltd. and Contributors
|
||||
# License: MIT. See LICENSE
|
||||
import os
|
||||
import re
|
||||
import json
|
||||
import shutil
|
||||
import re
|
||||
import subprocess
|
||||
from subprocess import getoutput
|
||||
from io import StringIO
|
||||
from tempfile import mkdtemp, mktemp
|
||||
from distutils.spawn import find_executable
|
||||
|
||||
import frappe
|
||||
from frappe.utils.minify import JavascriptMinify
|
||||
from subprocess import getoutput
|
||||
from tempfile import mkdtemp, mktemp
|
||||
from urllib.parse import urlparse
|
||||
|
||||
import click
|
||||
import psutil
|
||||
from urllib.parse import urlparse
|
||||
from semantic_version import Version
|
||||
from requests import head
|
||||
from requests.exceptions import HTTPError
|
||||
from semantic_version import Version
|
||||
|
||||
import frappe
|
||||
|
||||
timestamps = {}
|
||||
app_paths = None
|
||||
|
|
@ -32,6 +28,7 @@ class AssetsNotDownloadedError(Exception):
|
|||
class AssetsDontExistError(HTTPError):
|
||||
pass
|
||||
|
||||
|
||||
def download_file(url, prefix):
|
||||
from requests import get
|
||||
|
||||
|
|
@ -277,12 +274,14 @@ def check_node_executable():
|
|||
click.echo(f"{warn} Please install yarn using below command and try again.\nnpm install -g yarn")
|
||||
click.echo()
|
||||
|
||||
|
||||
def get_node_env():
|
||||
node_env = {
|
||||
"NODE_OPTIONS": f"--max_old_space_size={get_safe_max_old_space_size()}"
|
||||
}
|
||||
return node_env
|
||||
|
||||
|
||||
def get_safe_max_old_space_size():
|
||||
safe_max_old_space_size = 0
|
||||
try:
|
||||
|
|
@ -296,6 +295,7 @@ def get_safe_max_old_space_size():
|
|||
|
||||
return safe_max_old_space_size
|
||||
|
||||
|
||||
def generate_assets_map():
|
||||
symlinks = {}
|
||||
|
||||
|
|
@ -344,7 +344,6 @@ def clear_broken_symlinks():
|
|||
os.remove(path)
|
||||
|
||||
|
||||
|
||||
def unstrip(message: str) -> str:
|
||||
"""Pads input string on the right side until the last available column in the terminal
|
||||
"""
|
||||
|
|
@ -397,94 +396,6 @@ def link_assets_dir(source, target, hard_link=False):
|
|||
symlink(source, target, overwrite=True)
|
||||
|
||||
|
||||
def build(no_compress=False, verbose=False):
|
||||
for target, sources in get_build_maps().items():
|
||||
pack(os.path.join(assets_path, target), sources, no_compress, verbose)
|
||||
|
||||
|
||||
def get_build_maps():
|
||||
"""get all build.jsons with absolute paths"""
|
||||
# framework js and css files
|
||||
|
||||
build_maps = {}
|
||||
for app_path in app_paths:
|
||||
path = os.path.join(app_path, "public", "build.json")
|
||||
if os.path.exists(path):
|
||||
with open(path) as f:
|
||||
try:
|
||||
for target, sources in (json.loads(f.read() or "{}")).items():
|
||||
# update app path
|
||||
source_paths = []
|
||||
for source in sources:
|
||||
if isinstance(source, list):
|
||||
s = frappe.get_pymodule_path(source[0], *source[1].split("/"))
|
||||
else:
|
||||
s = os.path.join(app_path, source)
|
||||
source_paths.append(s)
|
||||
|
||||
build_maps[target] = source_paths
|
||||
except ValueError as e:
|
||||
print(path)
|
||||
print("JSON syntax error {0}".format(str(e)))
|
||||
return build_maps
|
||||
|
||||
|
||||
def pack(target, sources, no_compress, verbose):
|
||||
outtype, outtxt = target.split(".")[-1], ""
|
||||
jsm = JavascriptMinify()
|
||||
|
||||
for f in sources:
|
||||
suffix = None
|
||||
if ":" in f:
|
||||
f, suffix = f.split(":")
|
||||
if not os.path.exists(f) or os.path.isdir(f):
|
||||
print("did not find " + f)
|
||||
continue
|
||||
timestamps[f] = os.path.getmtime(f)
|
||||
try:
|
||||
with open(f, "r") as sourcefile:
|
||||
data = str(sourcefile.read(), "utf-8", errors="ignore")
|
||||
|
||||
extn = f.rsplit(".", 1)[1]
|
||||
|
||||
if (
|
||||
outtype == "js"
|
||||
and extn == "js"
|
||||
and (not no_compress)
|
||||
and suffix != "concat"
|
||||
and (".min." not in f)
|
||||
):
|
||||
tmpin, tmpout = StringIO(data.encode("utf-8")), StringIO()
|
||||
jsm.minify(tmpin, tmpout)
|
||||
minified = tmpout.getvalue()
|
||||
if minified:
|
||||
outtxt += str(minified or "", "utf-8").strip("\n") + ";"
|
||||
|
||||
if verbose:
|
||||
print("{0}: {1}k".format(f, int(len(minified) / 1024)))
|
||||
elif outtype == "js" and extn == "html":
|
||||
# add to frappe.templates
|
||||
outtxt += html_to_js_template(f, data)
|
||||
else:
|
||||
outtxt += "\n/*\n *\t%s\n */" % f
|
||||
outtxt += "\n" + data + "\n"
|
||||
|
||||
except Exception:
|
||||
print("--Error in:" + f + "--")
|
||||
print(frappe.get_traceback())
|
||||
|
||||
with open(target, "w") as f:
|
||||
f.write(outtxt.encode("utf-8"))
|
||||
|
||||
print("Wrote %s - %sk" % (target, str(int(os.path.getsize(target) / 1024))))
|
||||
|
||||
|
||||
def html_to_js_template(path, content):
|
||||
"""returns HTML template content as Javascript code, adding it to `frappe.templates`"""
|
||||
return """frappe.templates["{key}"] = '{content}';\n""".format(
|
||||
key=path.rsplit("/", 1)[-1][:-5], content=scrub_html_template(content))
|
||||
|
||||
|
||||
def scrub_html_template(content):
|
||||
"""Returns HTML content with removed whitespace and comments"""
|
||||
# remove whitespace to a single space
|
||||
|
|
@ -496,37 +407,7 @@ def scrub_html_template(content):
|
|||
return content.replace("'", "\'")
|
||||
|
||||
|
||||
def files_dirty():
|
||||
for target, sources in get_build_maps().items():
|
||||
for f in sources:
|
||||
if ":" in f:
|
||||
f, suffix = f.split(":")
|
||||
if not os.path.exists(f) or os.path.isdir(f):
|
||||
continue
|
||||
if os.path.getmtime(f) != timestamps.get(f):
|
||||
print(f + " dirty")
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
|
||||
def compile_less():
|
||||
if not find_executable("lessc"):
|
||||
return
|
||||
|
||||
for path in app_paths:
|
||||
less_path = os.path.join(path, "public", "less")
|
||||
if os.path.exists(less_path):
|
||||
for fname in os.listdir(less_path):
|
||||
if fname.endswith(".less") and fname != "variables.less":
|
||||
fpath = os.path.join(less_path, fname)
|
||||
mtime = os.path.getmtime(fpath)
|
||||
if fpath in timestamps and mtime == timestamps[fpath]:
|
||||
continue
|
||||
|
||||
timestamps[fpath] = mtime
|
||||
|
||||
print("compiling {0}".format(fpath))
|
||||
|
||||
css_path = os.path.join(path, "public", "css", fname.rsplit(".", 1)[0] + ".css")
|
||||
os.system("lessc {0} > {1}".format(fpath, css_path))
|
||||
def html_to_js_template(path, content):
|
||||
"""returns HTML template content as Javascript code, adding it to `frappe.templates`"""
|
||||
return """frappe.templates["{key}"] = '{content}';\n""".format(
|
||||
key=path.rsplit("/", 1)[-1][:-5], content=scrub_html_template(content))
|
||||
|
|
|
|||
|
|
@ -1,212 +0,0 @@
|
|||
|
||||
# This code is original from jsmin by Douglas Crockford, it was translated to
|
||||
# Python by Baruch Even. The original code had the following copyright and
|
||||
# license.
|
||||
#
|
||||
# /* jsmin.c
|
||||
# 2007-05-22
|
||||
#
|
||||
# Copyright (c) 2002 Douglas Crockford (www.crockford.com)
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
# this software and associated documentation files (the "Software"), to deal in
|
||||
# the Software without restriction, including without limitation the rights to
|
||||
# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
# of the Software, and to permit persons to whom the Software is furnished to do
|
||||
# so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in all
|
||||
# copies or substantial portions of the Software.
|
||||
#
|
||||
# The Software shall be used for Good, not Evil.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
# SOFTWARE.
|
||||
# */
|
||||
|
||||
from io import StringIO
|
||||
|
||||
def jsmin(js):
|
||||
ins = StringIO(js)
|
||||
outs = StringIO()
|
||||
JavascriptMinify().minify(ins, outs)
|
||||
str = outs.getvalue()
|
||||
if len(str) > 0 and str[0] == '\n':
|
||||
str = str[1:]
|
||||
return str
|
||||
|
||||
def isAlphanum(c):
|
||||
"""return true if the character is a letter, digit, underscore,
|
||||
dollar sign, or non-ASCII character.
|
||||
"""
|
||||
return ((c >= 'a' and c <= 'z') or (c >= '0' and c <= '9') or
|
||||
(c >= 'A' and c <= 'Z') or c == '_' or c == '$' or c == '\\' or (c is not None and ord(c) > 126));
|
||||
|
||||
class UnterminatedComment(Exception):
|
||||
pass
|
||||
|
||||
class UnterminatedStringLiteral(Exception):
|
||||
pass
|
||||
|
||||
class UnterminatedRegularExpression(Exception):
|
||||
pass
|
||||
|
||||
class JavascriptMinify(object):
|
||||
|
||||
def _outA(self):
|
||||
self.outstream.write(self.theA)
|
||||
def _outB(self):
|
||||
self.outstream.write(self.theB)
|
||||
|
||||
def _get(self):
|
||||
"""return the next character from stdin. Watch out for lookahead. If
|
||||
the character is a control character, translate it to a space or
|
||||
linefeed.
|
||||
"""
|
||||
c = self.theLookahead
|
||||
self.theLookahead = None
|
||||
if c is None:
|
||||
c = self.instream.read(1)
|
||||
if c >= ' ' or c == '\n':
|
||||
return c
|
||||
if c == '': # EOF
|
||||
return '\000'
|
||||
if c == '\r':
|
||||
return '\n'
|
||||
return ' '
|
||||
|
||||
def _peek(self):
|
||||
self.theLookahead = self._get()
|
||||
return self.theLookahead
|
||||
|
||||
def _next(self):
|
||||
"""get the next character, excluding comments. peek() is used to see
|
||||
if an unescaped '/' is followed by a '/' or '*'.
|
||||
"""
|
||||
c = self._get()
|
||||
if c == '/' and self.theA != '\\':
|
||||
p = self._peek()
|
||||
if p == '/':
|
||||
c = self._get()
|
||||
while c > '\n':
|
||||
c = self._get()
|
||||
return c
|
||||
if p == '*':
|
||||
c = self._get()
|
||||
while 1:
|
||||
c = self._get()
|
||||
if c == '*':
|
||||
if self._peek() == '/':
|
||||
self._get()
|
||||
return ' '
|
||||
if c == '\000':
|
||||
raise UnterminatedComment()
|
||||
|
||||
return c
|
||||
|
||||
def _action(self, action):
|
||||
"""do something! What you do is determined by the argument:
|
||||
1 Output A. Copy B to A. Get the next B.
|
||||
2 Copy B to A. Get the next B. (Delete A).
|
||||
3 Get the next B. (Delete B).
|
||||
action treats a string as a single character. Wow!
|
||||
action recognizes a regular expression if it is preceded by ( or , or =.
|
||||
"""
|
||||
if action <= 1:
|
||||
self._outA()
|
||||
|
||||
if action <= 2:
|
||||
self.theA = self.theB
|
||||
if self.theA == "'" or self.theA == '"':
|
||||
while 1:
|
||||
self._outA()
|
||||
self.theA = self._get()
|
||||
if self.theA == self.theB:
|
||||
break
|
||||
if self.theA <= '\n':
|
||||
raise UnterminatedStringLiteral()
|
||||
if self.theA == '\\':
|
||||
self._outA()
|
||||
self.theA = self._get()
|
||||
|
||||
|
||||
if action <= 3:
|
||||
self.theB = self._next()
|
||||
if self.theB == '/' and (self.theA == '(' or self.theA == ',' or
|
||||
self.theA == '=' or self.theA == ':' or
|
||||
self.theA == '[' or self.theA == '?' or
|
||||
self.theA == '!' or self.theA == '&' or
|
||||
self.theA == '|' or self.theA == ';' or
|
||||
self.theA == '{' or self.theA == '}' or
|
||||
self.theA == '\n'):
|
||||
self._outA()
|
||||
self._outB()
|
||||
while 1:
|
||||
self.theA = self._get()
|
||||
if self.theA == '/':
|
||||
break
|
||||
elif self.theA == '\\':
|
||||
self._outA()
|
||||
self.theA = self._get()
|
||||
elif self.theA <= '\n':
|
||||
raise UnterminatedRegularExpression()
|
||||
self._outA()
|
||||
self.theB = self._next()
|
||||
|
||||
|
||||
def _jsmin(self):
|
||||
"""Copy the input to the output, deleting the characters which are
|
||||
insignificant to JavaScript. Comments will be removed. Tabs will be
|
||||
replaced with spaces. Carriage returns will be replaced with linefeeds.
|
||||
Most spaces and linefeeds will be removed.
|
||||
"""
|
||||
self.theA = '\n'
|
||||
self._action(3)
|
||||
|
||||
while self.theA != '\000':
|
||||
if self.theA == ' ':
|
||||
if isAlphanum(self.theB):
|
||||
self._action(1)
|
||||
else:
|
||||
self._action(2)
|
||||
elif self.theA == '\n':
|
||||
if self.theB in ['{', '[', '(', '+', '-']:
|
||||
self._action(1)
|
||||
elif self.theB == ' ':
|
||||
self._action(3)
|
||||
else:
|
||||
if isAlphanum(self.theB):
|
||||
self._action(1)
|
||||
else:
|
||||
self._action(2)
|
||||
else:
|
||||
if self.theB == ' ':
|
||||
if isAlphanum(self.theA):
|
||||
self._action(1)
|
||||
else:
|
||||
self._action(3)
|
||||
elif self.theB == '\n':
|
||||
if self.theA in ['}', ']', ')', '+', '-', '"', '\'']:
|
||||
self._action(1)
|
||||
else:
|
||||
if isAlphanum(self.theA):
|
||||
self._action(1)
|
||||
else:
|
||||
self._action(3)
|
||||
else:
|
||||
self._action(1)
|
||||
|
||||
def minify(self, instream, outstream):
|
||||
self.instream = instream
|
||||
self.outstream = outstream
|
||||
self.theA = '\n'
|
||||
self.theB = None
|
||||
self.theLookahead = None
|
||||
|
||||
self._jsmin()
|
||||
self.instream.close()
|
||||
Loading…
Add table
Reference in a new issue