Forking what is left of ZeroNet and hopefully adding an AT Proto Frontend/Proxy
1import os
2import subprocess
3import re
4import logging
5import time
6import functools
7
8from Config import config
9from util import helper
10
11
12# Find files with extension in path
13def findfiles(path, find_ext):
14 def sorter(f1, f2):
15 f1 = f1[0].replace(path, "")
16 f2 = f2[0].replace(path, "")
17 if f1 == "":
18 return 1
19 elif f2 == "":
20 return -1
21 else:
22 return helper.cmp(f1.lower(), f2.lower())
23
24 for root, dirs, files in sorted(os.walk(path, topdown=False), key=functools.cmp_to_key(sorter)):
25 for file in sorted(files):
26 file_path = root + "/" + file
27 file_ext = file.split(".")[-1]
28 if file_ext in find_ext and not file.startswith("all."):
29 yield file_path.replace("\\", "/")
30
31
32# Try to find coffeescript compiler in path
33def findCoffeescriptCompiler():
34 coffeescript_compiler = None
35 try:
36 import distutils.spawn
37 coffeescript_compiler = helper.shellquote(distutils.spawn.find_executable("coffee")) + " --no-header -p"
38 except:
39 pass
40 if coffeescript_compiler:
41 return coffeescript_compiler
42 else:
43 return False
44
45
46# Generates: all.js: merge *.js, compile coffeescript, all.css: merge *.css, vendor prefix features
47def merge(merged_path):
48 merged_path = merged_path.replace("\\", "/")
49 merge_dir = os.path.dirname(merged_path)
50 s = time.time()
51 ext = merged_path.split(".")[-1]
52 if ext == "js": # If merging .js find .coffee too
53 find_ext = ["js", "coffee"]
54 else:
55 find_ext = [ext]
56
57 # If exist check the other files modification date
58 if os.path.isfile(merged_path):
59 merged_mtime = os.path.getmtime(merged_path)
60 else:
61 merged_mtime = 0
62
63 changed = {}
64 for file_path in findfiles(merge_dir, find_ext):
65 if os.path.getmtime(file_path) > merged_mtime + 1:
66 changed[file_path] = True
67 if not changed:
68 return # Assets not changed, nothing to do
69
70 old_parts = {}
71 if os.path.isfile(merged_path): # Find old parts to avoid unncessary recompile
72 merged_old = open(merged_path, "rb").read()
73 for match in re.findall(rb"(/\* ---- (.*?) ---- \*/(.*?)(?=/\* ----|$))", merged_old, re.DOTALL):
74 old_parts[match[1].decode()] = match[2].strip(b"\n\r")
75
76 logging.debug("Merging %s (changed: %s, old parts: %s)" % (merged_path, changed, len(old_parts)))
77 # Merge files
78 parts = []
79 s_total = time.time()
80 for file_path in findfiles(merge_dir, find_ext):
81 file_relative_path = file_path.replace(merge_dir + "/", "")
82 parts.append(b"\n/* ---- %s ---- */\n\n" % file_relative_path.encode("utf8"))
83 if file_path.endswith(".coffee"): # Compile coffee script
84 if file_path in changed or file_relative_path not in old_parts: # Only recompile if changed or its not compiled before
85 if config.coffeescript_compiler is None:
86 config.coffeescript_compiler = findCoffeescriptCompiler()
87 if not config.coffeescript_compiler:
88 logging.error("No coffeescript compiler defined, skipping compiling %s" % merged_path)
89 return False # No coffeescript compiler, skip this file
90
91 # Replace / with os separators and escape it
92 file_path_escaped = helper.shellquote(file_path.replace("/", os.path.sep))
93
94 if "%s" in config.coffeescript_compiler: # Replace %s with coffeescript file
95 command = config.coffeescript_compiler.replace("%s", file_path_escaped)
96 else: # Put coffeescript file to end
97 command = config.coffeescript_compiler + " " + file_path_escaped
98
99 # Start compiling
100 s = time.time()
101 compiler = subprocess.Popen(command, shell=True, stderr=subprocess.STDOUT, stdout=subprocess.PIPE)
102 out = compiler.stdout.read()
103 compiler.wait()
104 logging.debug("Running: %s (Done in %.2fs)" % (command, time.time() - s))
105
106 # Check errors
107 if out and out.startswith(b"("): # No error found
108 parts.append(out)
109 else: # Put error message in place of source code
110 error = out
111 logging.error("%s Compile error: %s" % (file_relative_path, error))
112 error_escaped = re.escape(error).replace(b"\n", b"\\n").replace(br"\\n", br"\n")
113 parts.append(
114 b"alert('%s compile error: %s');" %
115 (file_relative_path.encode(), error_escaped)
116 )
117 else: # Not changed use the old_part
118 parts.append(old_parts[file_relative_path])
119 else: # Add to parts
120 parts.append(open(file_path, "rb").read())
121
122 merged = b"\n".join(parts)
123 if ext == "css": # Vendor prefix css
124 from lib.cssvendor import cssvendor
125 merged = cssvendor.prefix(merged)
126 merged = merged.replace(b"\r", b"")
127 open(merged_path, "wb").write(merged)
128 logging.debug("Merged %s (%.2fs)" % (merged_path, time.time() - s_total))
129
130
131if __name__ == "__main__":
132 logging.getLogger().setLevel(logging.DEBUG)
133 os.chdir("..")
134 config.coffeescript_compiler = r'type "%s" | tools\coffee-node\bin\node.exe tools\coffee-node\bin\coffee --no-header -s -p'
135 merge("data/12Hw8rTgzrNo4DSh2AkqwPRqDyTticwJyH/js/all.js")