Skip to content

Commit 1b7e8f5

Browse files
authored
chore: refactor "installing" resources to ~/.ptx (#758)
* rename zip_templates to bundle_resources * wip * format * import bundle_resources tweak * remove deprecated templates module * formatting * lint * remove tests for deprecated templates module * clean up templates imports * fix set_ptx_path in core init * fix templates install * fix cli new * format * fix devscript alias * fix devscript * fix stale core.resources references * formatting * add sample article test * formatting * more accurate sample article checker * update core commit to get working sample article
1 parent ab453cb commit 1b7e8f5

19 files changed

Lines changed: 156 additions & 249 deletions

.devcontainer/postCreateCommand.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ echo 'export PATH="/root/.local/bin:$PATH"' > ~/.bashrc
88
sudo `which poetry` config virtualenvs.create false
99
sudo `which poetry` install --with dev
1010
python scripts/fetch_core.py
11-
python scripts/zip_templates.py
11+
python scripts/bundle_resources.py
1212
playwright install-deps
1313
playwright install
1414
# Run mypy once so that it will install any needed type stubs. After this, the VSCode extension will run it automatically.

.github/workflows/tests.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ jobs:
2020
run: |
2121
python -m pip install -e .
2222
python scripts/fetch_core.py
23-
python scripts/zip_templates.py
23+
python scripts/bundle_resources.py
2424
- name: Check formatting with black
2525
run: python -m black --check --diff $(git ls-files "*.py")
2626
- name: Check for lint
@@ -75,7 +75,7 @@ jobs:
7575
run: |
7676
python -m poetry install
7777
python -m poetry run python scripts/fetch_core.py
78-
python -m poetry run python scripts/zip_templates.py
78+
python -m poetry run python scripts/bundle_resources.py
7979
8080
- name: Test with pytest
8181
run: |

.gitignore

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -138,11 +138,8 @@ cython_debug/
138138

139139
#pretext-core
140140
pretext/core/pretext.py
141-
pretext/core/resources.zip
142-
#shipped templates
143-
pretext/templates/resources
144-
#old "static" stuff (deprecated
145-
pretext/static
141+
#zipped resources
142+
pretext/resources/*.zip
146143

147144
#default new pretext project
148145
new-pretext-project

pretext/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121

2222
VERSION = get_version("pretext", Path(__file__).parent.parent)
2323

24-
CORE_COMMIT = "ed4e9d94a75b5b728aca2eb06dfde3f1595ab783"
24+
CORE_COMMIT = "ac1ca3ca67c9512059afd6fd37a714a7fc988a5d"
2525

2626

2727
def activate() -> None:

pretext/cli.py

Lines changed: 25 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525

2626
from . import (
2727
utils,
28-
templates,
28+
resources,
2929
core,
3030
constants,
3131
plastex,
@@ -248,7 +248,8 @@ def devscript(args: List[str]) -> None:
248248
"""
249249
PY_CMD = sys.executable
250250
subprocess.run(
251-
[PY_CMD, str(core.resources.path("pretext", "pretext"))] + list(args)
251+
[PY_CMD, str(resources.resource_base_path() / "core" / "pretext" / "pretext")]
252+
+ list(args)
252253
)
253254

254255

@@ -284,47 +285,35 @@ def new(template: str, directory: Path, url_template: str) -> None:
284285
"""
285286
directory_fullpath = Path(directory).resolve()
286287
if utils.project_path(directory_fullpath) is not None:
287-
log.warning(
288+
log.error(
288289
f"A project already exists in `{utils.project_path(directory_fullpath)}`."
289290
)
290-
log.warning("No new project will be generated.")
291+
log.error("No new project will be generated.")
291292
return
292-
log.info(
293-
f"Generating new PreTeXt project in `{directory_fullpath}` using `{template}` template."
294-
)
293+
log.info(f"Generating new PreTeXt project in `{directory_fullpath}`")
294+
directory_fullpath.mkdir(exist_ok=True)
295295
if url_template is not None:
296+
log.info(f"Using template at `{url_template}`")
297+
# get project and extract to directory
296298
r = requests.get(url_template)
297299
archive = zipfile.ZipFile(io.BytesIO(r.content))
300+
with tempfile.TemporaryDirectory(prefix="pretext_") as tmpdirname:
301+
archive.extractall(tmpdirname)
302+
content_path = [Path(tmpdirname) / i for i in os.listdir(tmpdirname)][0]
303+
shutil.copytree(content_path, directory_fullpath, dirs_exist_ok=True)
298304
else:
299-
with templates.resource_path(f"{template}.zip") as template_path:
300-
archive = zipfile.ZipFile(template_path)
301-
# find (first) project.ptx to use as root of template
302-
filenames = [Path(filepath).name for filepath in archive.namelist()]
303-
project_ptx_index = filenames.index("project.ptx")
304-
project_ptx_path = Path(archive.namelist()[project_ptx_index])
305-
project_dir_path = project_ptx_path.parent
306-
with tempfile.TemporaryDirectory(prefix="pretext_") as tmpdirname:
307-
temp_path = Path(tmpdirname) / "new-project"
308-
temp_path.mkdir()
309-
for filepath in [
310-
filepath
311-
for filepath in archive.namelist()
312-
if project_dir_path in Path(filepath).parents
313-
]:
314-
archive.extract(filepath, path=temp_path)
315-
tmpsubdirname = temp_path / project_dir_path
316-
shutil.copytree(tmpsubdirname, directory_fullpath, dirs_exist_ok=True)
317-
# generate remaining boilerplate like requirements.txt
318-
project = Project.parse(directory_fullpath)
319-
project.generate_boilerplate(update_requirements=True)
320-
if len(project.targets) == 0:
321-
log.warning("The generated project has no targets!")
322-
else:
323-
target = project.targets[0]
324-
log.info(f"Success! Open `{target.source_abspath()}` to edit your document")
325-
log.info(
326-
f"Then try to `pretext build` and `pretext view` from within `{directory_fullpath}`."
327-
)
305+
log.info(f"Using `{template}` template.")
306+
# copy project from installed resources
307+
with resources.resource_base_path() / "templates" / f"{template}" as template_path:
308+
shutil.copytree(template_path, directory_fullpath, dirs_exist_ok=True)
309+
# generate missing boilerplate
310+
with utils.working_directory(directory_fullpath):
311+
project_path = utils.project_path()
312+
if project_path is None:
313+
project = Project()
314+
else:
315+
project = Project.parse(project_path)
316+
project.generate_boilerplate(update_requirements=True)
328317

329318

330319
# pretext init

pretext/core/__init__.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,10 @@
77
"Run `scripts/fetch_core.py` to grab a copy of pretex core.\n"
88
"The original error message is: " + e.msg
99
)
10-
from . import resources
10+
from .. import resources
1111
from .. import CORE_COMMIT, VERSION
1212

13-
set_ptx_path(resources.path())
13+
set_ptx_path(resources.resource_base_path() / "core")
1414

1515

1616
def cli_build_message() -> str:

pretext/core/resources.py

Lines changed: 0 additions & 43 deletions
This file was deleted.

pretext/project/__init__.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
from .. import codechat
2525
from .. import utils
2626
from .. import types as pt # PreTeXt types
27-
from .. import templates
27+
from ..resources import resource_base_path
2828
from .. import VERSION
2929

3030

@@ -286,7 +286,7 @@ def post_validate(self) -> None:
286286
if not self.publication_abspath().exists():
287287
# ... then use the CLI's built-in template file.
288288
# TODO: this is wrong, since the returned path is only valid inside the context manager. Instead, need to enter the context here, then exit it when this class is deleted (also problematic).
289-
with templates.resource_path("publication.ptx") as self.publication:
289+
with resource_base_path() / "templates" / "publication.ptx" as self.publication:
290290
pass
291291
# Otherwise, verify that the provided publication file exists. TODO: It is silly to check that all publication files exist. We warn when they don't. If the target we are calling has a non-existent publication file, then that error will be caught anyway.
292292
else:
@@ -1455,7 +1455,7 @@ def generate_boilerplate(
14551455
f"Your existing {resource} file has been backed up at {backup_resource_path}."
14561456
)
14571457
if resource != "requirements.txt":
1458-
with templates.resource_path(resource) as resource_path:
1458+
with resource_base_path() / "templates" / resource as resource_path:
14591459
if (
14601460
not project_resource_path.exists()
14611461
or resource_path.read_text()

pretext/resources/__init__.py

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import importlib.resources
2+
import logging
3+
from pathlib import Path
4+
import shutil
5+
import zipfile
6+
7+
from .. import VERSION, CORE_COMMIT
8+
9+
log = logging.getLogger("ptxlogger")
10+
11+
_RESOURCE_BASE_PATH = Path.home() / ".ptx" / VERSION
12+
13+
14+
def install(reinstall: bool = False) -> None:
15+
if _RESOURCE_BASE_PATH.exists():
16+
if reinstall:
17+
log.info(f"Deleting existing resources at {_RESOURCE_BASE_PATH}")
18+
shutil.rmtree(_RESOURCE_BASE_PATH)
19+
else:
20+
log.warning(f"Resources are already installed at {_RESOURCE_BASE_PATH}")
21+
return
22+
_RESOURCE_BASE_PATH.mkdir(parents=True)
23+
24+
log.info("Installing core resources")
25+
with importlib.resources.path("pretext.resources", "core.zip") as static_zip:
26+
with zipfile.ZipFile(static_zip, "r") as zip:
27+
zip.extractall(path=_RESOURCE_BASE_PATH)
28+
(_RESOURCE_BASE_PATH / f"pretext-{CORE_COMMIT}").rename(
29+
_RESOURCE_BASE_PATH / "core"
30+
)
31+
32+
log.info("Installing templates")
33+
(_RESOURCE_BASE_PATH / "templates").mkdir()
34+
with importlib.resources.path("pretext.resources", "templates.zip") as static_zip:
35+
with zipfile.ZipFile(static_zip, "r") as zip:
36+
zip.extractall(path=_RESOURCE_BASE_PATH / "templates")
37+
38+
39+
def resource_base_path() -> Path:
40+
if not _RESOURCE_BASE_PATH.exists():
41+
log.info(f"Installing resources to {_RESOURCE_BASE_PATH}")
42+
install()
43+
return _RESOURCE_BASE_PATH

pretext/templates/__init__.py

Lines changed: 0 additions & 28 deletions
This file was deleted.

0 commit comments

Comments
 (0)