chore: Fix shenanigans with builder

This commit is contained in:
Théophile Diot 2024-08-09 19:03:41 +01:00
parent 055e005b34
commit 5ae6b09dd2
No known key found for this signature in database
GPG key ID: FA995104A0BA376A
5 changed files with 120 additions and 117 deletions

View file

@ -1,6 +1,6 @@
# See https://pre-commit.com for more information
# See https://pre-commit.com/hooks.html for more hooks
exclude: (^LICENSE.md$|^src/VERSION$|^env/|^src/(bw/misc/root-ca.pem$|deps/src/|common/core/modsecurity/files|ui/static/(js/(editor/|utils/purify/|tsparticles\.bundle\.min\.js)|css/dashboard\.css))|\.(svg|drawio|patch\d?|ascii|tf|tftpl|key)$)
exclude: (^src/ui/client|^LICENSE.md$|^src/VERSION$|^env/|^src/(bw/misc/root-ca.pem$|deps/src/|common/core/modsecurity/files|ui/static/(js/(editor/|utils/purify/|tsparticles\.bundle\.min\.js)|css/dashboard\.css))|\.(svg|drawio|patch\d?|ascii|tf|tftpl|key)$)
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: 2c9f875913ee60ca25ce70243dc24d5b6415598c # frozen: v4.6.0

View file

@ -6,6 +6,8 @@ from pathlib import Path
from re import sub
from typing import List
from utils import run_command
# get current directory
current_directory = Path.cwd()
# needed dirs
@ -47,29 +49,6 @@ def set_setup():
move_template(opt_dir_setup_page, ui_dir_templates)
def run_command(command: List[str]) -> int:
"""Utils to run a subprocess command. This is usefull to run npm commands to build vite project"""
print(f"Running command: {command}", flush=True)
try:
process = Popen(command, stdout=PIPE, stderr=PIPE, cwd=current_directory.as_posix(), shell=not bool(getenv("DOCKERFILE", "")))
while process.poll() is None:
if process.stdout is not None:
for line in process.stdout:
print(line.decode("utf-8").strip(), flush=True)
if process.returncode != 0:
print("Error while running command", flush=True)
print(process.stdout.read().decode("utf-8"), flush=True)
print(process.stderr.read().decode("utf-8"), flush=True)
return 1
except BaseException as e:
print(f"Error while running command: {e}", flush=True)
return 1
print("Command executed successfully", flush=True)
return 0
def remove_dir(directory: Path):
"""Utils function to remove a directory if exists"""
if directory.exists():
@ -153,9 +132,10 @@ def add_legacy():
def add_builder_and_widgets():
# First we want to generate widgets by executing "widgets_generator.py" that is on same level
if run_command(["/usr/bin/python3", "widgets_generator.py"]):
if run_command(["python", "widgets_generator.py"]):
exit(1)
if run_command(["/usr/bin/python3", "widgets_generator.py"], current_directory):
if run_command(["python3", "widgets_generator.py"], current_directory):
if run_command(["python", "widgets_generator.py"], current_directory):
exit(1)
# Create output folders
copytree(builder_dir_pages.as_posix(), ui_dir_builder.as_posix())
@ -164,14 +144,18 @@ def add_builder_and_widgets():
# I want to replace "from .utils." by "from builder.utils."
content = file.read_text()
content = content.replace("from .utils.", "from builder.utils.")
content = """from os.path import join, sep
content = content.replace("# from src.", "from src.")
content = (
"""from os.path import join, sep
from sys import path as sys_path
for deps_path in [join(sep, "usr", "share", "bunkerweb", *paths) for paths in (("deps", "python"), ("utils",), ("api",), ("db",))]:
if deps_path not in sys_path:
sys_path.append(deps_path)
""" + content
"""
+ content
)
file.write_text(content)
copytree(builder_dir_utils.as_posix(), ui_dir_builder_utils.as_posix())
@ -184,14 +168,14 @@ def build():
add_legacy()
# Only install packages if not already installed
if not current_directory.joinpath("node_modules").exists():
if run_command(["/usr/bin/npm", "install"]):
if run_command(["npm", "install"]):
if run_command(["/usr/bin/npm", "install"], current_directory):
if run_command(["npm", "install"], current_directory):
exit(1)
if run_command(["/usr/bin/npm", "run", "build-dashboard"]):
if run_command(["npm", "run", "build-dashboard"]):
if run_command(["/usr/bin/npm", "run", "build-dashboard"], current_directory):
if run_command(["npm", "run", "build-dashboard"], current_directory):
exit(1)
set_dashboard()
# run_command(["/usr/bin/npm", "run", "build-setup"])
# run_command(["/usr/bin/npm", "run", "build-setup"], current_directory)
# set_setup()
add_builder_and_widgets()

View file

@ -1,5 +1,9 @@
from .utils.widgets import instance_widget
from typing import List
# from src.instance import Instance
def instances_builder(instances: List[Instance]) -> str:
"""
@ -9,8 +13,8 @@ def instances_builder(instances: List[Instance]) -> str:
for instance in instances:
# setup actions buttons
actions = ["reload", "stop"] if instance.status == "up" else ["start"]
actions = ["reload", "stop"] if instance.status == "up" else ["start"]
buttons = [
{
"attrs": {

31
src/ui/client/utils.py Normal file
View file

@ -0,0 +1,31 @@
from os import getenv
from pathlib import Path
from subprocess import PIPE, Popen
from typing import List, Optional
def run_command(command: List[str], current_directory: Optional[Path] = None, *, with_output: bool = False) -> int:
"""Utils to run a subprocess command. This is usefull to run npm commands to build vite project"""
print(f"Running command: {command}", flush=True)
try:
process = Popen(
command, stdout=PIPE, stderr=PIPE, cwd=current_directory.as_posix() if current_directory else None, shell=not bool(getenv("DOCKERFILE", ""))
)
while process.poll() is None:
if not with_output and process.stdout is not None:
for line in process.stdout:
print(line.decode("utf-8").strip(), flush=True)
if process.returncode != 0:
print("Error while running command", flush=True)
print(process.stdout.read().decode("utf-8"), flush=True)
print(process.stderr.read().decode("utf-8"), flush=True)
return 1
except BaseException as e:
print(f"Error while running command: {e}", flush=True)
return 1
print("Command executed successfully", flush=True)
if with_output:
return process.stdout.read().decode("utf-8")
return 0

View file

@ -1,11 +1,15 @@
from os import cpu_count
from os.path import abspath
from pathlib import Path
from subprocess import Popen, PIPE
from threading import Semaphore, Thread
from traceback import format_exc
from typing import List
from shutil import rmtree
from re import search, sub
from typing import Union
from utils import run_command
# We want to get path of the folder where our components are
# The path is "../src/client/dashboard/src/components" from here
@ -13,36 +17,15 @@ inputFolder = abspath("../client/dashboard/components")
outputFolderMd = abspath("../client/.widgets-md")
outputFolderPy = abspath("../client/.widgets")
outputFolderWidgets = abspath("../client/builder/utils")
components_path_to_exclude = ("\components\Icons\\", "components\Forms\Error\\", "\components\Dashboard\\", "\components\Builder\\")
def run_command(command: List[str]) -> int:
"""Utils to run a subprocess command. This is usefull to run npm commands to build vite project"""
print(f"Running command: {command}", flush=True)
try:
process = Popen(command, stdout=PIPE, stderr=PIPE, shell=True, text=True)
while process.poll() is None:
if process.stdout is not None:
for line in process.stdout:
print(line.strip(), flush=True)
if process.returncode != 0:
print("Error while running command", flush=True)
print(process.stdout.read(), flush=True)
print(process.stderr.read(), flush=True)
return 1
except BaseException as e:
print(f"Error while running command: {e}", flush=True)
return 1
print("Command executed successfully", flush=True)
return 0
components_path_to_exclude = ("components/Icons", "components/Forms/Error", "components/Dashboard", "components/Builder")
def install_npm_packages():
"""Install all packages needed to run the script"""
# Install documentation package
run_command("npm install -g documentation")
if run_command(["/usr/bin/npm", "install", "-g", "documentation"]):
if run_command(["npm", "install", "-g", "documentation"]):
exit(1)
def reset():
@ -53,7 +36,6 @@ def reset():
rmtree(outputFolderPy, ignore_errors=True)
def vue2js():
"""Get the script part of a Vue file and create a JS file"""
# Create outputFolder if not exists
@ -65,7 +47,7 @@ def vue2js():
continue
# Exclude some files
if any(folder_path in str(folder) for folder_path in components_path_to_exclude):
if any(folder_path in folder.as_posix() for folder_path in components_path_to_exclude):
continue
# Read the file content
@ -73,8 +55,8 @@ def vue2js():
# Get only the content between <script setup> and </script> tag
script = data.split("<script setup>")[1].split("</script>")[0]
# Get index of jsdoc comments
first_doc_index_start = script.index("/**")
first_doc_index_end = script.index("*/")
first_doc_index_start = script.find("/**")
first_doc_index_end = script.find("*/")
if first_doc_index_start != -1 and first_doc_index_end != -1:
# get content before first_doc_index_end
script = script[first_doc_index_start : first_doc_index_end + 2]
@ -87,33 +69,40 @@ def vue2js():
def js2md():
"""Run a command to render markdown from JS files"""
# Get all files from the output folder
files = list(Path(outputFolderMd).rglob("*"))
process_list = []
# Create a markdown file for each JS file
for file in files:
# Run a process `documentation build <filename> -f md > <filename>.md
command = f"documentation build {file} -f md > {file.with_suffix('.md')}"
# Run the command
# I want to run this command async
process = Popen(command, stdout=PIPE, stderr=PIPE, shell=True, text=True)
process_list.append(process)
semaphore = Semaphore(cpu_count())
def convert_json_to_md(file: Path):
semaphore.acquire()
# Run the command
output = run_command(["documentation", "build", file.as_posix(), "-f", "md"], with_output=True)
if output == 1:
print("Error while running command", flush=True)
exit(1)
# Create a new file with the same name but with .md extension
file.with_suffix(".md").write_text(output)
semaphore.release()
threads = []
# Create a markdown file for each JS file
for file in Path(outputFolderMd).rglob("*"):
threads.append(Thread(target=convert_json_to_md, args=(file,)))
for thread in threads:
thread.start()
for thread in threads:
thread.join()
# Wait that all processes are done
for process in process_list:
process.wait()
# Remove js files after
for file in files:
file.unlink()
# rmtree(outputFolderMd, ignore_errors=True)
def formatMd():
"""Format each markdown file to remove useless data and format some data like params"""
# Get all files from the output folder
files = list(Path(outputFolderMd).rglob("*"))
# Create order using the tag title path of each file
order = []
for file in files:
for file in Path(outputFolderMd).rglob("*"):
try:
# Get the title from first line
data = file.read_text()
@ -122,8 +111,9 @@ def formatMd():
# Remove ### Table of contents
data = data.replace("### Table of Contents", "")
# Remove everything before the first ## tag
index = data.index("## ")
data = data[index:]
if "## " in data:
index = data.index("## ")
data = data[index:]
# I want to loop on each line
lines = data.split("\n")
@ -132,8 +122,8 @@ def formatMd():
# remove space (so &#x20 or &#32)
line = line.replace("&#x20", "").replace("&#32", "")
if line.startswith("#") and ".vue" in line and "\.vue" in line:
line = line.replace("\.vue", ".vue")
if line.startswith("#") and ".vue" in line and "\\.vue" in line:
line = line.replace("\\.vue", ".vue")
# Case not a param, keep the line as is
if not line.startswith("*"):
@ -158,18 +148,18 @@ def formatMd():
data = "\n".join(line_result)
# update the file with the new content
file.write_text(data)
except:
print("Error while parsing file", str(file.name))
continue
except BaseException:
print(format_exc(), flush=True)
print("Error while parsing file", str(file.name), flush=True)
exit(1)
def md2py():
# create py folder if not exists
Path(outputFolderPy).mkdir(parents=True, exist_ok=True)
# Get all files from the output folder
files = list(Path(outputFolderMd).rglob("*"))
# Create order using the tag title path of each file
for file in files:
for file in Path(outputFolderMd).rglob("*"):
data = file.read_text()
# Get the title from first line, after the ## tag
try:
@ -183,13 +173,13 @@ def md2py():
widget = create_widget(title, desc, params)
Path(f"{outputFolderPy}/{title.capitalize()}.py").write_text(widget)
except BaseException as e:
print(e)
print("Error while parsing file", str(file.name))
continue
except BaseException:
print(format_exc(), flush=True)
print("Error while parsing file", str(file.name), flush=True)
exit(1)
# Remove widgets-md
# rmtree(outputFolderMd, ignore_errors=True)
rmtree(outputFolderMd, ignore_errors=True)
def get_py_title(data: str) -> str:
@ -262,9 +252,9 @@ def get_py_params(data: str) -> Union[str, bool]:
# remove default key if None
return list_params
except BaseException as e:
print(e)
print("Error while parsing params")
except BaseException:
print(format_exc(), flush=True)
print("Error while parsing params", flush=True)
def convert_params(params: List[dict]) -> List[dict]:
@ -329,9 +319,9 @@ def convert_params(params: List[dict]) -> List[dict]:
convert_params = sorted(convert_params, key=lambda x: x.get("type") is not None)
return convert_params
except BaseException as e:
print(e)
print("Error while converting params")
except BaseException:
print(format_exc(), flush=True)
print("Error while converting params", flush=True)
def create_widget(title: str, desc: str, params: List[dict]):
@ -401,10 +391,9 @@ def {f_title}_widget(
return {{ "type" : "{title.lower().capitalize()}", "data" : data }}
"""
return widget_function
except BaseException as e:
print(e)
print("Error while creating widget")
except BaseException:
print(format_exc(), flush=True)
print("Error while creating widget", flush=True)
def merge_widgets():
@ -423,8 +412,7 @@ def add_key_value(data, key, value, default):
data[key] = value
"""
# get all files from the output folder
files = list(Path(outputFolderPy).rglob("*"))
for file in files:
for file in Path(outputFolderPy).rglob("*.py"):
data = file.read_text()
content += data
content += "\n"
@ -436,16 +424,12 @@ def add_key_value(data, key, value, default):
Path(f"{outputFolderWidgets}/widgets.py").write_text(content)
# Remove py folder
rmtree(outputFolderPy, ignore_errors=True)
# Remove md folder
rmtree(outputFolderMd, ignore_errors=True)
# install_npm_packages()
install_npm_packages()
reset()
vue2js()
js2md()
formatMd()
md2py()
merge_widgets()
# reset()