Is there a hook for bench build?

I have a custom python script that generates a custom myapp/public/icons.svg to be loaded in hooks.py (Frappe v15 feature).

I’m currently running the script manually but i think it makes more sense to make it part of the build process somehow. i.e. when i run bench build --apps myapp.

That way I don’t have to version control the generated myapp/public/icons.svg file while also being assured the server will always have the latest version for it.

I know there’s patches but I’m unsure if that’s the right feature for my use case as the script will need to be run on every bench build, vs just once.

1 Like

You can probably try build commmand for this. Bench build executes build command for all apps.

Hi, thanks for the reply! I like the approach but that would involve rewriting my script to JS though right?

My app currently doesn’t have any JS dependencies at all (mostly just customises Desk) so I was wondering if I can retain my Python script :sweat_smile:

BTW, in case anyone stumbles upon this, here’s my script. It’s not particularly complex per se so converting to JS is certainly a valid option. I just figured I should try to keep it simple without JS dependencies for my particular use case.

pyproject.toml

# These dependencies are only installed when developer mode is enabled
[tool.bench.dev-dependencies]
# package_name = "~=1.1.0"
beautifulsoup4 = "4.12.2"
lxml = "4.9.3"
soupsieve = "2.5"

compile.py

import os
from bs4 import BeautifulSoup

input_dir = "./symbols"
output_file_path = "../../myapp/public/icons.svg"

# Start the combined SVG content
combined_svg_content = '<svg id="myapp-symbols" aria-hidden="true" style="position: absolute; width: 0; height: 0; overflow: hidden;" class="d-block" xmlns="http://www.w3.org/2000/svg">\n'

# Track used IDs for uniqueness check
used_ids = set()

# Track errors
errors = []

# Track if at least one valid symbol is found
valid_symbol_found = False

# Track valid symbol IDs
valid_symbol_ids = []

# Read each symbol file and append its content
for symbol_file in os.listdir(input_dir):
    if symbol_file.endswith('.svg'):
        file_path = os.path.join(input_dir, symbol_file)
        with open(file_path, 'r') as file:
            soup = BeautifulSoup(file.read(), 'xml')
            symbol_tag = soup.find('symbol')
            if symbol_tag:
                symbol_id = symbol_tag.get('id')
                if symbol_id:
                    # Check if the ID is correctly formatted
                    if not symbol_id.startswith("icon-myapp-"):
                        errors.append(f"Error: ID '{symbol_id}' in file '{symbol_file}' does not match the format 'icon-myapp-SOME_NAME'.")
                    # Check for uniqueness
                    elif symbol_id in used_ids:
                        errors.append(f"Error: Duplicate ID '{symbol_id}' found in file '{symbol_file}'.")
                    else:
                        used_ids.add(symbol_id)
                        valid_symbol_found = True
                        valid_symbol_ids.append(symbol_id)
                    combined_svg_content += str(symbol_tag) + "\n"
                else:
                    errors.append(f"Error: Symbol tag in file '{symbol_file}' does not have an 'id' attribute.")

# Close the SVG tag and write the combined content to the output file
combined_svg_content += '</svg>'

# Show errors
if errors:
    for error in errors:
        print(error)

# Display a message indicating the number of valid symbols found and whether the SVG was created
if valid_symbol_found:
    print(f"Found {len(valid_symbol_ids)} valid symbols. They've been compiled to icons.svg.")
    if valid_symbol_found:
        with open(output_file_path, 'w') as output_file:
            output_file.write(combined_svg_content)
else:
    print("No valid symbols found.")

# List valid symbol IDs in a row
if valid_symbol_ids:
    print("Valid symbol IDs:")
    print(", ".join(valid_symbol_ids))

You could probably use the after_migrate hook, at least in a production context. For local development you could use bench execute or develop a custom bench command instead.

You can technically just invoke your python script from a JS script. Not ideal but better than rewriting it.