Skip to content

Commit f67d241

Browse files
authored
Merge pull request #3 from PlasmoGenEpi/update_pmo_app
Update pmo app
2 parents 9e17053 + 59ed663 commit f67d241

File tree

5 files changed

+198
-1488
lines changed

5 files changed

+198
-1488
lines changed

.github/workflows/deploy.yml

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
name: Build and Deploy
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
workflow_dispatch: # Allow manual triggering
8+
9+
jobs:
10+
build-and-deploy:
11+
runs-on: ubuntu-latest
12+
permissions:
13+
contents: write
14+
15+
steps:
16+
- name: Checkout repository
17+
uses: actions/checkout@v4
18+
with:
19+
submodules: recursive
20+
token: ${{ secrets.GITHUB_TOKEN }}
21+
22+
- name: Set up Python
23+
uses: actions/setup-python@v4
24+
with:
25+
python-version: '3.11'
26+
27+
- name: Install dependencies
28+
run: |
29+
python -m pip install --upgrade pip
30+
pip install jinja2
31+
32+
- name: Build site
33+
run: |
34+
python build_site.py
35+
36+
- name: Commit and push built files
37+
if: github.ref == 'refs/heads/main'
38+
run: |
39+
git config --local user.email "action@github.com"
40+
git config --local user.name "GitHub Action"
41+
git add docs/
42+
git diff --staged --quiet || git commit -m "Build site from submodule [skip ci]"
43+
git push
44+

.gitignore

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
# Build artifacts - these are generated from source files during build
2+
# These will be regenerated by GitHub Actions on each deployment
3+
docs/app/
4+
docs/site-packages/
5+
docs/_setup_pmotools.py
6+
docs/index.html
7+
8+
# Keep docs/assets/ committed (contains wheel file needed for build)
9+
10+
# Python
11+
__pycache__/
12+
*.py[cod]
13+
*$py.class
14+
*.so
15+
.Python
16+
env/
17+
venv/
18+
ENV/
19+
.venv
20+
21+
# IDE
22+
.vscode/
23+
.idea/
24+
*.swp
25+
*.swo
26+
*~
27+
28+
# OS
29+
.DS_Store
30+
Thumbs.db
31+
32+
# Local test files
33+
*.log
34+

build_site.py

Lines changed: 85 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,16 @@
11
import jinja2
22
import os
33
import shutil
4+
import zipfile
45

56
requirements = [
67
"pandas",
78
"fuzzywuzzy",
89
"openpyxl",
9-
# TODO: remove this once the package is published
10-
"https://plasmogenepi.github.io/pmotool-app-web/assets/pmotools_python-0.1.0-py3-none-any.whl"
10+
# pmotools is extracted from wheel and included directly in filesystem
1111
]
1212

13+
1314
entrypoint = "PMO_Builder.py"
1415
build_dir = "docs"
1516

@@ -19,34 +20,97 @@ def build_site():
1920
with open(template_path, "r") as f:
2021
template = jinja2.Template(f.read())
2122

22-
# Load the python files in all subdirectories
23+
# Copy Python and JSON files from submodule to docs/app/ directory
24+
app_dir = os.path.join(build_dir, "app")
2325
parsed_files = []
26+
27+
# Copy Python files
2428
for root, dirs, files in os.walk("pmotools-app"):
2529
for file in files:
2630
if file.endswith(".py"):
27-
with open(os.path.join(root, file), "r") as f:
28-
file_name = os.path.join(root, file).replace("pmotools-app/", "")
29-
parsed_files.append({"name": file_name, "content": f"`{f.read()}`"})
31+
src_path = os.path.join(root, file)
32+
# Preserve directory structure relative to pmotools-app
33+
rel_path = os.path.relpath(src_path, "pmotools-app")
34+
dst_path = os.path.join(app_dir, rel_path)
35+
36+
# Create destination directory
37+
os.makedirs(os.path.dirname(dst_path), exist_ok=True)
38+
shutil.copy(src_path, dst_path)
39+
40+
# Store file path for template
41+
file_name = rel_path.replace("\\", "/") # Normalize path separators
42+
parsed_files.append({"name": file_name, "url": f"app/{file_name}"})
3043

31-
# Add the images to the parsed files
32-
for root, dirs, files in os.walk("pmotools-app"):
33-
for file in files:
34-
if file.endswith(".png"):
35-
file_name = os.path.join(root, file).replace("pmotools-app/", "")
36-
# copy the file to the build directory
37-
os.makedirs(os.path.join(build_dir, "images"), exist_ok=True)
38-
shutil.copy(os.path.join(root, file), os.path.join(build_dir, "images", file))
39-
build_url = f"images/{file}"
40-
parsed_files.append({"name": file_name, "content": {"url": build_url}})
41-
42-
# Add conf files to the parsed files
44+
# Copy JSON config files
4345
for root, dirs, files in os.walk("pmotools-app"):
4446
for file in files:
4547
if file.endswith(".json"):
46-
with open(os.path.join(root, file), "r") as f:
47-
file_name = os.path.join(root, file).replace("pmotools-app/", "")
48-
parsed_files.append({"name": file_name, "content": f"`{f.read()}`"})
48+
src_path = os.path.join(root, file)
49+
# Preserve directory structure relative to pmotools-app
50+
rel_path = os.path.relpath(src_path, "pmotools-app")
51+
dst_path = os.path.join(app_dir, rel_path)
52+
53+
# Create destination directory
54+
os.makedirs(os.path.dirname(dst_path), exist_ok=True)
55+
shutil.copy(src_path, dst_path)
56+
57+
# Store file path for template
58+
file_name = rel_path.replace("\\", "/") # Normalize path separators
59+
parsed_files.append({"name": file_name, "url": f"app/{file_name}"})
4960

61+
# Extract pmotools package from wheel and add to filesystem
62+
# This avoids installing dependencies that are already in requirements
63+
wheel_path = os.path.join(build_dir, "assets", "pmotools-0.1.0-py3-none-any.whl")
64+
if os.path.exists(wheel_path):
65+
with zipfile.ZipFile(wheel_path, 'r') as wheel:
66+
# Extract only pmotools package files (not dist-info)
67+
for member in wheel.namelist():
68+
if member.startswith('pmotools/') and not member.endswith('/'):
69+
# Extract to app directory (which is in Python path in stlite)
70+
# Store as site-packages/pmotools/... for proper Python import
71+
relative_path = member # This is already pmotools/...
72+
dst_path = os.path.join(app_dir, "site-packages", relative_path)
73+
os.makedirs(os.path.dirname(dst_path), exist_ok=True)
74+
75+
# Extract and write the file
76+
with wheel.open(member) as source:
77+
with open(dst_path, 'wb') as target:
78+
target.write(source.read())
79+
80+
# Add to parsed files for template
81+
file_name = relative_path.replace("\\", "/")
82+
parsed_files.append({"name": file_name, "url": f"app/site-packages/{file_name}"})
83+
84+
# Create __init__.py for site-packages if needed
85+
site_packages_init = os.path.join(app_dir, "site-packages", "__init__.py")
86+
if not os.path.exists(site_packages_init):
87+
os.makedirs(os.path.dirname(site_packages_init), exist_ok=True)
88+
with open(site_packages_init, 'w') as f:
89+
f.write("")
90+
91+
# Create a setup file to add site-packages to sys.path
92+
setup_file = os.path.join(app_dir, "_setup_pmotools.py")
93+
with open(setup_file, 'w') as f:
94+
f.write("""import sys
95+
import os
96+
# Add site-packages to Python path so pmotools can be imported
97+
site_packages = os.path.join(os.path.dirname(__file__), 'site-packages')
98+
if site_packages not in sys.path:
99+
sys.path.insert(0, site_packages)
100+
""")
101+
# Add setup file to parsed files
102+
parsed_files.append({"name": "_setup_pmotools.py", "url": "app/_setup_pmotools.py"})
103+
104+
# Modify PMO_Builder.py to import setup first
105+
pmo_builder_path = os.path.join(app_dir, "PMO_Builder.py")
106+
if os.path.exists(pmo_builder_path):
107+
with open(pmo_builder_path, 'r') as f:
108+
content = f.read()
109+
# Add import at the very beginning if not already present
110+
if "import _setup_pmotools" not in content:
111+
content = "import _setup_pmotools\n" + content
112+
with open(pmo_builder_path, 'w') as f:
113+
f.write(content)
50114

51115
# Render the template
52116
rendered = template.render(files=parsed_files, requirements=requirements, entrypoint=entrypoint)

0 commit comments

Comments
 (0)