Skip to content

Commit 39ac1f0

Browse files
authored
Merge pull request #403 – Move absolute_urls_to_freeze and CLI
#403
2 parents d0591b6 + 4799017 commit 39ac1f0

File tree

8 files changed

+108
-78
lines changed

8 files changed

+108
-78
lines changed

naucse/__init__.py

Lines changed: 0 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,43 +1,4 @@
1-
import logging
21
import sys
3-
from logging.handlers import RotatingFileHandler
4-
from pathlib import Path
5-
6-
from naucse.freezer import NaucseFreezer
72

83
if sys.version_info[0] <3 :
94
raise RuntimeError('We love Python 3.')
10-
11-
from naucse.cli import cli
12-
from naucse.views import app, lesson_static_generator
13-
14-
15-
def main():
16-
arca_log_path = Path(".arca/arca.log")
17-
arca_log_path.parent.mkdir(exist_ok=True)
18-
arca_log_path.touch()
19-
20-
naucse_log_path = Path(".arca/naucse.log")
21-
naucse_log_path.touch()
22-
23-
def get_handler(path, **kwargs):
24-
handler = RotatingFileHandler(path, **kwargs)
25-
formatter = logging.Formatter("[%(asctime)s] {%(pathname)s:%(lineno)d} %(levelname)s - %(message)s")
26-
27-
handler.setLevel(logging.INFO)
28-
handler.setFormatter(formatter)
29-
30-
return handler
31-
32-
logger = logging.getLogger("arca")
33-
logger.addHandler(get_handler(arca_log_path, maxBytes=10000, backupCount=0))
34-
35-
logger = logging.getLogger("naucse")
36-
logger.addHandler(get_handler(naucse_log_path))
37-
38-
freezer = NaucseFreezer(app)
39-
40-
# see the generator for details
41-
freezer.register_generator(lesson_static_generator)
42-
43-
cli(app, base_url='https://naucse.python.cz', freezer=freezer)

naucse/__main__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
from naucse import main
1+
from naucse.cli import main
22

33
main()

naucse/cli.py

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,14 @@
1+
import logging
2+
from pathlib import Path
3+
from logging.handlers import RotatingFileHandler
4+
15
import click
26
import elsa
37

48
from naucse.utils.views import forks_enabled, does_course_return_info
9+
from naucse.views import app, lesson_static_generator
10+
11+
from naucse.freezer import NaucseFreezer
512

613

714
def cli(app, *, base_url=None, freezer=None):
@@ -71,3 +78,34 @@ def fork_valid(course, suffix=""):
7178
cli = click.CommandCollection(sources=[naucse, elsa_group])
7279

7380
return cli()
81+
82+
83+
def main():
84+
arca_log_path = Path(".arca/arca.log")
85+
arca_log_path.parent.mkdir(exist_ok=True)
86+
arca_log_path.touch()
87+
88+
naucse_log_path = Path(".arca/naucse.log")
89+
naucse_log_path.touch()
90+
91+
def get_handler(path, **kwargs):
92+
handler = RotatingFileHandler(path, **kwargs)
93+
formatter = logging.Formatter("[%(asctime)s] {%(pathname)s:%(lineno)d} %(levelname)s - %(message)s")
94+
95+
handler.setLevel(logging.INFO)
96+
handler.setFormatter(formatter)
97+
98+
return handler
99+
100+
logger = logging.getLogger("arca")
101+
logger.addHandler(get_handler(arca_log_path, maxBytes=10000, backupCount=0))
102+
103+
logger = logging.getLogger("naucse")
104+
logger.addHandler(get_handler(naucse_log_path))
105+
106+
freezer = NaucseFreezer(app)
107+
108+
# see the generator for details
109+
freezer.register_generator(lesson_static_generator)
110+
111+
cli(app, base_url='https://naucse.python.cz', freezer=freezer)

naucse/freezer.py

Lines changed: 25 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,38 @@
11
import contextlib
2+
from collections import deque
23

4+
from flask import current_app
35
from flask_frozen import UrlForLogger, Freezer
46

5-
from naucse.utils.views import absolute_urls_to_freeze
7+
def record_url(url):
8+
"""Logs that `url` should be included in the resulting static site"""
9+
urls_to_freeze = current_app.config.get('NAUCSE_ABSOLUTE_URLS_TO_FREEZE')
10+
if urls_to_freeze is not None:
11+
urls_to_freeze.append(url)
612

713

814
class AllLinksLogger(UrlForLogger):
915
"""Logs ``url_for`` calls, but yields urls from ``absolute_urls_to_freeze`` as well.
1016
"""
1117

18+
def __init__(self, app, urls_to_freeze):
19+
super().__init__(app)
20+
self.naucse_urls_to_freeze = urls_to_freeze
21+
1222
def iter_calls(self):
1323
"""Yield all logged urls and links parsed from content.
1424
"""
1525
# Unfortunately, ``yield from`` cannot be used as the queues are
1626
# modified on the go.
17-
while self.logged_calls or absolute_urls_to_freeze:
18-
if self.logged_calls:
27+
while self.logged_calls or self.naucse_urls_to_freeze:
28+
while self.logged_calls:
1929
yield self.logged_calls.popleft()
20-
# prefer urls from :atrr:`logged_calls` - so, ideally,
21-
# cache is populated from the base repository
22-
continue
23-
if absolute_urls_to_freeze:
24-
yield absolute_urls_to_freeze.popleft()
30+
# Prefer URLs from logged_calls - ideally, cache is populated
31+
# from the base repository.
32+
# That means we only yield from urls_to_freeze
33+
# if there are no logged_calls.
34+
if self.naucse_urls_to_freeze:
35+
yield self.naucse_urls_to_freeze.popleft()
2536

2637

2738
@contextlib.contextmanager
@@ -45,5 +56,10 @@ class NaucseFreezer(Freezer):
4556
def __init__(self, app):
4657
super().__init__(app)
4758

59+
urls_to_freeze = deque()
60+
61+
with app.app_context():
62+
app.config['NAUCSE_ABSOLUTE_URLS_TO_FREEZE'] = urls_to_freeze
63+
4864
# override the default url_for_logger with our modified version
49-
self.url_for_logger = AllLinksLogger(app)
65+
self.url_for_logger = AllLinksLogger(app, urls_to_freeze)

naucse/models.py

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414
import naucse.utils.views
1515
from naucse.utils.models import Model, YamlProperty, DataProperty, DirProperty, MultipleModelDirProperty, ForkProperty
1616
from naucse.utils.models import reify, arca
17-
from naucse.utils.views import absolute_urls_to_freeze
1817
from naucse.validation import AllowedElementsParser
1918
from naucse.templates import setup_jinja_env, vars_functions
2019
from naucse.utils.markdown import convert_markdown
@@ -644,11 +643,6 @@ def render(self, page_type, *args, **kwargs):
644643
if page_type != "calendar_ics" and result.output["content"] is not None:
645644
allowed_elements_parser.reset_and_feed(result.output["content"])
646645

647-
if "urls" in result.output:
648-
# Freeze URLs generated by the code in fork, but only if
649-
# they start with the slug of the course
650-
absolute_urls_to_freeze.extend([url for url in result.output["urls"] if url.startswith(f"/{self.slug}/")])
651-
652646
return result.output
653647

654648
def render_course(self, **kwargs):
@@ -706,9 +700,9 @@ def validate_link(link, key):
706700
for link_type in "prev_link", "session_link", "next_link":
707701
link = result.output.get(link_type)
708702

709-
if isinstance(link, dict) and validate_link(link, "url") and validate_link(link, "title"):
710-
if link["url"].startswith(f"/{self.slug}/"):
711-
absolute_urls_to_freeze.append(link["url"])
703+
if (isinstance(link, dict) and
704+
validate_link(link, "url") and
705+
validate_link(link, "title")):
712706
to_return.append(link)
713707
else:
714708
to_return.append(None)

naucse/utils/views.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,12 @@
22
import hashlib
33
import json
44
import os
5-
from collections import deque, defaultdict
5+
from collections import defaultdict
66
from pathlib import Path
77

88
from arca.exceptions import PullError, BuildError, RequirementsMismatch
99
from arca.utils import get_hash_for_file
1010

11-
absolute_urls_to_freeze = deque()
12-
1311

1412
def get_recent_runs(course):
1513
"""Build a list of "recent" runs based on a course.

naucse/views.py

Lines changed: 39 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
from werkzeug.local import LocalProxy
1717

1818
from naucse import models
19-
from naucse.freezer import temporary_url_for_logger
19+
from naucse.freezer import temporary_url_for_logger, record_url
2020
from naucse.models import allowed_elements_parser
2121
from naucse.templates import setup_jinja_env, vars_functions
2222
from naucse.urlconverters import register_url_converters
@@ -26,7 +26,7 @@
2626
from naucse.utils.models import arca
2727
from naucse.utils.views import get_recent_runs, list_months
2828
from naucse.utils.views import does_course_return_info
29-
from naucse.utils.views import absolute_urls_to_freeze, raise_errors_from_forks
29+
from naucse.utils.views import raise_errors_from_forks
3030
from naucse.utils.views import page_content_cache_key, get_edit_info
3131
from naucse.validation import DisallowedStyle, DisallowedElement, InvalidHTML
3232

@@ -276,6 +276,13 @@ def lesson_static_generator():
276276
yield from lesson_static_generator_dir(lesson.slug, static, static)
277277

278278

279+
def record_content_urls(data_from_fork, prefix):
280+
# Freeze URLs generated by the code in fork, but only if
281+
# they start with the given prefix
282+
for url in data_from_fork.get("urls", ()):
283+
if url.startswith(prefix):
284+
record_url(url)
285+
279286
def course_content(course):
280287
def lesson_url(lesson, *args, **kwargs):
281288
if kwargs.get("page") == "index":
@@ -319,6 +326,7 @@ def course(course):
319326
root_slug=model.meta.slug,
320327
travis_build_id=os.environ.get("TRAVIS_BUILD_ID"),
321328
)
329+
record_content_urls(data_from_fork, f"/{course.slug}/")
322330
kwargs = {
323331
"course_content": content,
324332
"edit_info": edit_info,
@@ -464,7 +472,6 @@ def content_creator():
464472
subpage_url=subpage_url,
465473
vars=variables
466474
)
467-
468475
absolute_urls = [url_for(logged[0], **logged[1]) for logged in logger.logged_calls]
469476

470477
relative_urls = [get_relative_url(request.path, x) for x in absolute_urls]
@@ -485,11 +492,10 @@ def content_creator():
485492
content_key = page_content_cache_key(Repo("."), lesson.slug, page.slug, solution, variables)
486493
cached = arca.region.get_or_create(content_key, content_creator)
487494

488-
# The urls are added twice to ``absolute_urls_to_freeze``
489-
# when the content is created.
495+
# The urls are recorded twice when the content is created.
490496
# But it doesn't matter, duplicate URLs are skipped.
491-
absolute_urls = [urljoin(request.path, x) for x in cached["urls"]]
492-
absolute_urls_to_freeze.extend(absolute_urls)
497+
for x in cached["urls"]:
498+
record_url(urljoin(request.path, x))
493499

494500
return cached
495501

@@ -530,20 +536,23 @@ def course_page(course, lesson, page, solution=None):
530536
if content_offer:
531537
fork_kwargs["content_key"] = content_key
532538

533-
data_from_fork = course.render_page(lesson_slug, page, solution, **fork_kwargs)
539+
data_from_fork = course.render_page(
540+
lesson_slug, page, solution,
541+
**fork_kwargs)
542+
record_content_urls(data_from_fork, f"/{course.slug}/")
534543

535544
content = data_from_fork["content"]
536545

537546
if content is None:
538547
# the offer was accepted
539548
content = content_offer["content"]
540-
absolute_urls_to_freeze.extend([urljoin(request.path, x)
541-
for x in content_offer["urls"]])
549+
for x in content_offer["urls"]:
550+
record_url(urljoin(request.path, x))
542551
else:
543552
# the offer was rejected or the the fragment was not in cache
544553
arca.region.set(content_key, {"content": content, "urls": data_from_fork["content_urls"]})
545-
absolute_urls_to_freeze.extend([urljoin(request.path, x)
546-
for x in data_from_fork["content_urls"]])
554+
for x in data_from_fork["content_urls"]:
555+
record_url(urljoin(request.path, x))
547556

548557
# compatibility
549558
page = process_page_data(data_from_fork.get("page"))
@@ -573,8 +582,17 @@ def course_page(course, lesson, page, solution=None):
573582
title = '{}: {}'.format(course.title, page.title)
574583

575584
try:
576-
prev_link, session_link, next_link = course.get_footer_links(lesson.slug, page_slug,
577-
request_url=request.path)
585+
footer_links = course.get_footer_links(
586+
lesson.slug,
587+
page_slug,
588+
request_url=request.path,
589+
)
590+
for link in footer_links:
591+
_prefix = f"/{course.slug}/"
592+
if link and link["url"].startswith(_prefix):
593+
record_url(link["url"])
594+
prev_link, session_link, next_link = footer_links
595+
578596
except POSSIBLE_FORK_EXCEPTIONS as e:
579597
if raise_errors_from_forks():
580598
raise
@@ -726,7 +744,9 @@ def session_coverpage(course, session, coverpage):
726744
naucse.utils.views.forks_raise_if_disabled()
727745

728746
try:
729-
data_from_fork = course.render_session_coverpage(session, coverpage, request_url=request.path)
747+
data_from_fork = course.render_session_coverpage(
748+
session, coverpage, request_url=request.path)
749+
record_content_urls(data_from_fork, f"/{course.slug}/")
730750

731751
content = data_from_fork.get("content")
732752
if content is None:
@@ -790,6 +810,7 @@ def course_calendar(course):
790810

791811
try:
792812
data_from_fork = course.render_calendar(request_url=request.path)
813+
record_content_urls(data_from_fork, f"/{course.slug}/")
793814

794815
course = process_course_data(data_from_fork.get("course"), slug=course.slug)
795816
edit_info = links.process_edit_info(data_from_fork.get("edit_info"))
@@ -865,7 +886,9 @@ def course_calendar_ics(course):
865886
naucse.utils.views.forks_raise_if_disabled()
866887

867888
try:
868-
data_from_fork = course.render_calendar_ics(request_url=request.path)
889+
data_from_fork = course.render_calendar_ics(
890+
request_url=request.path)
891+
record_content_urls(data_from_fork, f"/{course.slug}/")
869892

870893
calendar = data_from_fork.get("calendar")
871894

test_naucse/test_forks.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,7 @@ def client(model, mocker):
183183
delattr(model, "safe_run_years")
184184

185185
mocker.patch("naucse.views._cached_model", model)
186-
from naucse import app
186+
from naucse.views import app
187187
app.testing = True
188188
yield app.test_client()
189189

0 commit comments

Comments
 (0)