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.

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.