diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index fc34a4c..e1f24bd 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -13,16 +13,43 @@ jobs: steps: - uses: actions/checkout@v4 - - name: Download Tectonic - run: - wget "https://github.com/tectonic-typesetting/tectonic/releases/download/tectonic%400.15.0/tectonic-0.15.0-x86_64-unknown-linux-musl.tar.gz" && - tar -xf "tectonic-0.15.0-x86_64-unknown-linux-musl.tar.gz" + # Could instead install `texlive-full`, but that takes ~20 minutes. + # We'll specify the packages we need manually. + - name: "Install TeXLive" + run: | + sudo apt update + DEBIAN_FRONTEND=noninteractive \ + sudo apt install --yes \ + texlive texlive-xetex \ + texlive-games texlive-fonts-extra texlive-latex-extra \ + texlive-pictures texlive-pstricks - - name: Build LaTeX handouts - run: bash build.sh + - name: "Download Typst" + run: | + wget -q "https://github.com/typst/typst/releases/download/v0.12.0/typst-x86_64-unknown-linux-musl.tar.xz" + tar -xf "typst-x86_64-unknown-linux-musl.tar.xz" + mv "typst-x86_64-unknown-linux-musl/typst" . + rm "typst-x86_64-unknown-linux-musl.tar.xz" + rm -dr "typst-x86_64-unknown-linux-musl" - - uses: actions/upload-artifact@v3 + # Builds all handouts, LaTeX and Typst + - name: "Build handouts" + run: TYPST_PATH="$(pwd)/typst" python tools/build/main.py + + # Upload logs, even if build fails. + # LaTeX stdout/stderr isn't always helpful. + - name: "Save LaTeX logs" + uses: actions/upload-artifact@v3 + if: always() with: - name: output + name: "LaTeX logs" + path: "**/*.log" + retention-days: 1 + + # Upload build output + - name: "Save output" + uses: actions/upload-artifact@v3 + with: + name: "Build output" path: "output/*" retention-days: 10 diff --git a/Warm-Ups/What's an AST?/main.tex b/Warm-Ups/What's an AST/main.tex similarity index 100% rename from Warm-Ups/What's an AST?/main.tex rename to Warm-Ups/What's an AST/main.tex diff --git a/Warm-Ups/What's an AST?/meta.toml b/Warm-Ups/What's an AST/meta.toml similarity index 100% rename from Warm-Ups/What's an AST?/meta.toml rename to Warm-Ups/What's an AST/meta.toml diff --git a/tools/build/main.py b/tools/build/main.py index 2bd7257..0d7aa47 100644 --- a/tools/build/main.py +++ b/tools/build/main.py @@ -16,10 +16,15 @@ ROOT: Path = Path(os.getcwd()) ### CONFIGURATION OUT_DIR: Path = ROOT / "output" -TYPST_PATH = "typst" -XETEX_PATH = "xelatex" +TYPST_PATH: str = "typst" +XETEX_PATH: str = "xelatex" ### END CONFIGURATION +# Allow path override +_env = os.environ.get("TYPST_PATH") +if isinstance(_env, str): + TYPST_PATH = _env + def log(msg): print(f"[BUILD.PY] {msg}") @@ -49,6 +54,10 @@ MetaToml = TypedDict( ) +def sanitize_file_name(file: str) -> str: + return file.replace("?", "") + + def read_meta_toml(file: Path) -> MetaToml: with file.open("rb") as f: base = tomllib.load(f) @@ -127,6 +136,7 @@ def build_typst(source_dir: Path, out_subdir: Path) -> IndexEntry | None: out = OUT_DIR / out_subdir out.mkdir(parents=True, exist_ok=True) + file_name = sanitize_file_name(f"{meta['title']}.pdf") res = subprocess.run( [ TYPST_PATH, @@ -135,7 +145,7 @@ def build_typst(source_dir: Path, out_subdir: Path) -> IndexEntry | None: "main.typ", "--input", "show_solutions=false", - f"{out}/{meta['title']}.pdf", + f"{out}/{file_name}", ], cwd=source_dir, stdout=subprocess.PIPE, @@ -148,13 +158,14 @@ def build_typst(source_dir: Path, out_subdir: Path) -> IndexEntry | None: # Build solutions if meta["publish_solutions"]: log(f"Building typst (solutions): {source_dir}") + file_name = sanitize_file_name(f"{meta['title']}.sols.pdf") res = subprocess.run( [ TYPST_PATH, "compile", "--ignore-system-fonts", "main.typ", - f"{out}/{meta['title']}.sols.pdf", + f"{out}/{file_name}", ], cwd=source_dir, stdout=subprocess.PIPE, @@ -208,7 +219,12 @@ def build_xetex(source_dir: Path, out_subdir: Path) -> IndexEntry | None: stderr=subprocess.PIPE, ) - shutil.copy(source_dir / "main.pdf", f"{out}/{meta['title']}.pdf") + file_name = sanitize_file_name(f"{meta['title']}.pdf") + try: + shutil.copy(source_dir / "main.pdf", f"{out}/{file_name}") + except Exception as e: + log(f"Error: {e}") + log_error(res) if res.returncode != 0: log_error(res) @@ -227,7 +243,12 @@ def build_xetex(source_dir: Path, out_subdir: Path) -> IndexEntry | None: stderr=subprocess.PIPE, ) - shutil.copy(source_dir / "main.pdf", f"{out}/{meta['title']}.sols.pdf") + file_name = sanitize_file_name(f"{meta['title']}.sols.pdf") + try: + shutil.copy(source_dir / "main.pdf", f"{out}/{file_name}") + except Exception as e: + log(f"Error: {e}") + log_error(res) if res.returncode != 0: log_error(res) @@ -278,6 +299,7 @@ def build_dir(base: str, out_sub: str, index: list[IndexEntry]): index: list[IndexEntry] = [] +index.extend(build_dir("Warm-Ups", "Warm-Ups", index)) index.extend(build_dir("Advanced", "Advanced", index)) index.extend(build_dir("Intermediate", "Intermediate", index))