Skip to content

Commit bef3e8c

Browse files
Copilotvgoehler
andauthored
feat: download upstream release PDFs; skip liaex PDF generation when all covered
- Add scripts/download_upstream_pdfs.sh: fetches PDF assets from GitHub Releases for each course, downloads missing files, writes .cache/<course>_upstream_pdfs manifest, exits 0 when at least one upstream PDF found. - Update scripts/generate_courses.sh: calls download_upstream_pdfs.sh per course; compares manifest count vs YAML lesson count to decide whether to pass --project-generate-pdf to liaex. - Update scripts/prune_pdfs.sh: reads .cache/*_upstream_pdfs manifests and adds listed files to the keep-set so human-readable upstream PDFs are never pruned. - Update Makefile: add download-pdfs-% pattern rule and download-pdfs aggregate target; insert download-pdfs-$(1) into force-build chain; make build-$(1) conditionally skip --project-generate-pdf when .cache/<course>_skip_pdf_gen flag is present. - Update .github/workflows/generateOERoverview.yml: pass GITHUB_TOKEN env var to the generate step so API calls are authenticated. Agent-Logs-Url: https://github.com/TUBAF-IfI-LiaScript/TUBAF-IfI-LiaScript.github.io/sessions/6d799220-3d5f-4288-8c91-c0766451b799 Co-authored-by: vgoehler <1705385+vgoehler@users.noreply.github.com>
1 parent b1861e3 commit bef3e8c

5 files changed

Lines changed: 197 additions & 10 deletions

File tree

.github/workflows/generateOERoverview.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ jobs:
3434

3535
- name: Generate missing course websites
3636
if: steps.changes.outputs.courses_to_generate != ''
37+
env:
38+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
3739
run: bash scripts/generate_courses.sh "${{ steps.changes.outputs.courses_to_generate }}"
3840

3941
- name: Display deployment summary

Makefile

Lines changed: 36 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ $(1): $(1).yml
1717
echo "📄 Using existing $(1).html and assets"; \
1818
fi
1919

20-
force-build-$(1): clean-$(1) build-$(1) organize-$(1) update-cache-$(1) mark-changed
20+
force-build-$(1): clean-$(1) download-pdfs-$(1) build-$(1) organize-$(1) update-cache-$(1) mark-changed
2121

2222
clean-$(1):
2323
@echo "🧹 Cleaning old files for $(1)..."
@@ -28,8 +28,14 @@ clean-$(1):
2828

2929
build-$(1):
3030
$(if $(filter $(1),$(PDF_COURSES)), \
31-
liaex --input $(1).yml --output $(1) --format project --project-generate-pdf --scorm-organization $(SCORM_ORG) --scorm-embed --scorm-masteryScore $(SCORM_SCORE), \
32-
liaex --input $(1).yml --output $(1) --format project)
31+
if [ -f ".cache/$(1)_skip_pdf_gen" ]; then \
32+
echo "🔨 Building $(1) (all PDFs from upstream)..."; \
33+
liaex --input $(1).yml --output $(1) --format project --scorm-organization $(SCORM_ORG) --scorm-embed --scorm-masteryScore $(SCORM_SCORE) --project-category-blur; \
34+
else \
35+
echo "🔨 Building $(1) with PDF generation..."; \
36+
liaex --input $(1).yml --output $(1) --format project --project-generate-pdf --scorm-organization $(SCORM_ORG) --scorm-embed --scorm-masteryScore $(SCORM_SCORE) --project-category-blur; \
37+
fi, \
38+
liaex --input $(1).yml --output $(1) --format project --project-category-blur)
3339

3440
organize-$(1):
3541
$(if $(filter $(1),$(PDF_COURSES)), \
@@ -39,6 +45,31 @@ endef
3945
# Generate targets for all courses
4046
$(foreach course,$(COURSES),$(eval $(call build_course,$(course))))
4147

48+
# Download upstream release PDFs for a single course.
49+
# Creates .cache/<course>_skip_pdf_gen when all lessons are covered by upstream PDFs.
50+
download-pdfs-%:
51+
@if [ -n "$(filter $*,$(PDF_COURSES))" ]; then \
52+
mkdir -p .cache; \
53+
[ -x scripts/download_upstream_pdfs.sh ] || chmod +x scripts/download_upstream_pdfs.sh; \
54+
LESSON_COUNT=$$(grep -c '^\s*- url:' "$*.yml" 2>/dev/null || echo 0); \
55+
if bash scripts/download_upstream_pdfs.sh "$*"; then \
56+
UPSTREAM_COUNT=$$(wc -l < ".cache/$*_upstream_pdfs" 2>/dev/null | tr -d ' ' || echo 0); \
57+
if [ "$$UPSTREAM_COUNT" -ge "$$LESSON_COUNT" ] && [ "$$LESSON_COUNT" -gt 0 ]; then \
58+
touch ".cache/$*_skip_pdf_gen"; \
59+
echo "✅ All $$UPSTREAM_COUNT upstream PDFs present for $* – PDF generation will be skipped"; \
60+
else \
61+
rm -f ".cache/$*_skip_pdf_gen"; \
62+
echo "📄 $$UPSTREAM_COUNT/$$LESSON_COUNT upstream PDFs for $* – PDF generation needed"; \
63+
fi; \
64+
else \
65+
rm -f ".cache/$*_skip_pdf_gen"; \
66+
echo "📄 No upstream PDFs for $* – PDF generation needed"; \
67+
fi; \
68+
fi
69+
70+
# Download upstream PDFs for all PDF courses (useful for local mode: make download-pdfs)
71+
download-pdfs: $(foreach course,$(PDF_COURSES),download-pdfs-$(course))
72+
4273
mark-changed:
4374
@touch .cache/build_occurred
4475

@@ -173,6 +204,7 @@ help:
173204
@echo " status - Show build status of all courses"
174205
@echo " git-update - Update git repository"
175206
@echo " prune-pdfs - Remove PDFs not referenced by any HTML"
207+
@echo " download-pdfs - Download upstream release PDFs for all PDF courses"
176208
@echo ""
177209
@echo "Individual courses (with change detection):"
178210
@$(foreach course,$(COURSES),echo " $(course)";)
@@ -185,7 +217,7 @@ help:
185217
@echo " SCORM org: $(SCORM_ORG)"
186218
@echo " SCORM score: $(SCORM_SCORE)"
187219

188-
.PHONY: all clean-all clean-cache force-all status git-update help prune-pdfs $(COURSES)
220+
.PHONY: all clean-all clean-cache force-all status git-update help prune-pdfs download-pdfs $(COURSES)
189221

190222
prune-pdfs:
191223
@echo "🗑️ Pruning unreferenced PDFs..."

scripts/download_upstream_pdfs.sh

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
#!/usr/bin/env bash
2+
# Download PDF release assets for a course from its upstream GitHub repository.
3+
#
4+
# Usage: ./scripts/download_upstream_pdfs.sh <course_name>
5+
# Env: GITHUB_TOKEN – optional, used to authenticate API calls and avoid rate-limiting
6+
#
7+
# Outputs:
8+
# assets/<course>/pdf/<name>.pdf – downloaded files (only when not already present)
9+
# .cache/<course>_upstream_pdfs – manifest: one PDF filename per line
10+
#
11+
# Exit codes:
12+
# 0 – at least one upstream PDF was found / downloaded
13+
# 1 – no upstream PDF release assets exist for this course
14+
15+
set -euo pipefail
16+
17+
COURSE="${1:-}"
18+
if [ -z "$COURSE" ]; then
19+
echo "Usage: $0 <course_name>" >&2
20+
exit 1
21+
fi
22+
23+
# Map course name → upstream repository name
24+
case "$COURSE" in
25+
digitalesysteme) REPO_NAME="EingebetteteSysteme" ;;
26+
prozprog) REPO_NAME="ProzeduraleProgrammierung" ;;
27+
softwareentwicklung) REPO_NAME="Softwareentwicklung" ;;
28+
robotikprojekt) REPO_NAME="SoftwareprojektRobotik" ;;
29+
*)
30+
echo "ℹ️ No upstream repo mapped for course '$COURSE'" >&2
31+
exit 1
32+
;;
33+
esac
34+
35+
REPO_ORG="TUBAF-IfI-LiaScript"
36+
API_URL="https://api.github.com/repos/${REPO_ORG}/VL_${REPO_NAME}/releases?per_page=100"
37+
PDF_DIR="assets/${COURSE}/pdf"
38+
MANIFEST=".cache/${COURSE}_upstream_pdfs"
39+
40+
mkdir -p "$PDF_DIR" .cache
41+
42+
# Build auth header if token is available
43+
CURL_AUTH=()
44+
if [ -n "${GITHUB_TOKEN:-}" ]; then
45+
CURL_AUTH=(-H "Authorization: Bearer ${GITHUB_TOKEN}")
46+
fi
47+
48+
echo "🔍 Checking upstream releases for VL_${REPO_NAME}..."
49+
API_RESPONSE=$(curl -sL --connect-timeout 15 "${CURL_AUTH[@]}" "$API_URL" 2>/dev/null)
50+
51+
# Check for API error / rate-limit response
52+
if echo "$API_RESPONSE" | grep -q '"message"' && ! echo "$API_RESPONSE" | grep -q '"assets"'; then
53+
MSG=$(echo "$API_RESPONSE" | grep -o '"message":"[^"]*"' | head -1 | sed 's/"message":"//;s/"$//')
54+
echo "⚠️ GitHub API error: ${MSG:-unknown error}" >&2
55+
exit 1
56+
fi
57+
58+
# Extract PDF asset names and their download URLs.
59+
# Deduplicate by name (keep first occurrence = most-recent release wins).
60+
if ! command -v jq >/dev/null 2>&1; then
61+
echo "⚠️ jq is not installed – cannot parse GitHub release assets" >&2
62+
exit 1
63+
fi
64+
65+
mapfile -t ALL_NAMES < <(
66+
echo "$API_RESPONSE" \
67+
| jq -r '.[].assets[] | select(.name | endswith(".pdf")) | .name' 2>/dev/null \
68+
|| true
69+
)
70+
mapfile -t ALL_URLS < <(
71+
echo "$API_RESPONSE" \
72+
| jq -r '.[].assets[] | select(.name | endswith(".pdf")) | .browser_download_url' 2>/dev/null \
73+
|| true
74+
)
75+
76+
if [ "${#ALL_NAMES[@]}" -eq 0 ]; then
77+
echo "ℹ️ No PDF release assets found for VL_${REPO_NAME}"
78+
rm -f "$MANIFEST"
79+
exit 1
80+
fi
81+
82+
# Deduplicate: keep the first occurrence of each filename
83+
declare -A SEEN
84+
NAMES=()
85+
URLS=()
86+
for i in "${!ALL_NAMES[@]}"; do
87+
name="${ALL_NAMES[$i]}"
88+
if [ -z "${SEEN[$name]+x}" ]; then
89+
SEEN["$name"]=1
90+
NAMES+=("$name")
91+
URLS+=("${ALL_URLS[$i]}")
92+
fi
93+
done
94+
95+
echo "📦 Found ${#NAMES[@]} unique upstream PDF(s) for ${COURSE}"
96+
97+
# Download missing PDFs and build manifest
98+
downloaded=0
99+
already_present=0
100+
> "${MANIFEST}.tmp"
101+
102+
for i in "${!NAMES[@]}"; do
103+
name="${NAMES[$i]}"
104+
url="${URLS[$i]}"
105+
target="${PDF_DIR}/${name}"
106+
107+
echo "${name}" >> "${MANIFEST}.tmp"
108+
109+
if [ -f "$target" ]; then
110+
already_present=$((already_present + 1))
111+
else
112+
echo " ⬇️ Downloading ${name}..."
113+
curl -sL --connect-timeout 30 "${CURL_AUTH[@]}" -o "$target" "$url"
114+
downloaded=$((downloaded + 1))
115+
fi
116+
done
117+
118+
# Atomically replace manifest
119+
mv "${MANIFEST}.tmp" "$MANIFEST"
120+
121+
echo "✅ Upstream PDFs: ${downloaded} downloaded, ${already_present} already present"
122+
exit 0

scripts/generate_courses.sh

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ set -euo pipefail
66

77
IFS=' ' read -ra course_list <<< "$1"
88

9+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
10+
911
echo "=== Generating Courses ==="
1012

1113
for course in "${course_list[@]}"; do
@@ -19,16 +21,34 @@ for course in "${course_list[@]}"; do
1921

2022
echo "Generating $html_file from $yaml_file..."
2123

22-
# Check whether PDFs already exist for this course
23-
pdf_dir="assets/${course}/pdf"
24+
# Determine whether PDF generation is needed for this course
2425
needs_pdfs=false
26+
manifest=".cache/${course}_upstream_pdfs"
2527

2628
if [ "$course" != "index" ]; then
27-
if [ ! -d "$pdf_dir" ] || [ -z "$(ls -A "$pdf_dir" 2>/dev/null)" ]; then
28-
needs_pdfs=true
29-
echo "📄 PDFs missing for $course - will generate"
29+
# Try to download upstream PDFs (creates/updates the manifest)
30+
if bash "$SCRIPT_DIR/download_upstream_pdfs.sh" "$course"; then
31+
# Count lessons and compare with upstream PDF coverage
32+
lesson_count=$(grep -c '^\s*- url:' "$yaml_file" 2>/dev/null || echo 0)
33+
upstream_count=$(wc -l < "$manifest" 2>/dev/null | tr -d ' ' || echo 0)
34+
35+
if [ "$upstream_count" -ge "$lesson_count" ] && [ "$lesson_count" -gt 0 ]; then
36+
echo "✅ All ${upstream_count} upstream PDFs available for ${course} – skipping PDF generation"
37+
needs_pdfs=false
38+
else
39+
echo "📄 ${upstream_count}/${lesson_count} upstream PDFs for ${course} – will generate remaining"
40+
needs_pdfs=true
41+
fi
3042
else
31-
echo "✅ PDFs already exist for $course - skipping generation"
43+
# No upstream PDFs available or mapping not found
44+
pdf_dir="assets/${course}/pdf"
45+
if [ ! -d "$pdf_dir" ] || [ -z "$(ls -A "$pdf_dir" 2>/dev/null)" ]; then
46+
echo "📄 No upstream PDFs and no local PDFs for ${course} – will generate"
47+
needs_pdfs=true
48+
else
49+
echo "✅ No upstream PDFs but local PDFs exist for ${course} – skipping generation"
50+
needs_pdfs=false
51+
fi
3252
fi
3353
fi
3454

scripts/prune_pdfs.sh

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,17 @@ while IFS= read -r rel; do
3030
keep["$abs"]=1
3131
done < <(printf "%s\n" "$referenced")
3232

33+
# Also protect upstream PDFs listed in .cache/*_upstream_pdfs manifests
34+
for manifest in .cache/*_upstream_pdfs; do
35+
[ -f "$manifest" ] || continue
36+
course="$(basename "$manifest" _upstream_pdfs)"
37+
while IFS= read -r pdf_name; do
38+
[[ -z "$pdf_name" ]] && continue
39+
abs="$repo_root/assets/${course}/pdf/${pdf_name}"
40+
keep["$abs"]=1
41+
done < "$manifest"
42+
done
43+
3344
# Find all PDFs under assets/**/pdf
3445
mapfile -t all_pdfs < <(find assets -type f -name '*.pdf')
3546

0 commit comments

Comments
 (0)