Merge branch 'master' of ssh://git.betalupi.com:33/Mark/ormc-handouts
This commit is contained in:
		
							
								
								
									
										6
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										6
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							@@ -4,13 +4,11 @@ __pycache__
 | 
				
			|||||||
*-ignore
 | 
					*-ignore
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Output files
 | 
					# Output files
 | 
				
			||||||
 | 
					/output
 | 
				
			||||||
 | 
					/output.zip
 | 
				
			||||||
main.pdf
 | 
					main.pdf
 | 
				
			||||||
**/build
 | 
					**/build
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# CI files
 | 
					 | 
				
			||||||
/_build
 | 
					 | 
				
			||||||
/_output
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# TeX build files
 | 
					# TeX build files
 | 
				
			||||||
*.synctex.gz*
 | 
					*.synctex.gz*
 | 
				
			||||||
*.latexmk
 | 
					*.latexmk
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8,7 +8,7 @@ Create a multiplication table for $\mathbb{Z}_4$:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
\begin{center}
 | 
					\begin{center}
 | 
				
			||||||
\begin{tabular}{c | c c c c}
 | 
					\begin{tabular}{c | c c c c}
 | 
				
			||||||
	\times & 0 & 1 & 2 & 3 \\
 | 
						$\times$ & 0 & 1 & 2 & 3 \\
 | 
				
			||||||
	\hline
 | 
						\hline
 | 
				
			||||||
	0 & ? & ? & ? & ? \\
 | 
						0 & ? & ? & ? & ? \\
 | 
				
			||||||
	1 & ? & ? & ? & ? \\
 | 
						1 & ? & ? & ? & ? \\
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -220,10 +220,10 @@
 | 
				
			|||||||
		Show that for any two functions $g: Y \to W$ and $h: Y \to W$, if
 | 
							Show that for any two functions $g: Y \to W$ and $h: Y \to W$, if
 | 
				
			||||||
		$g \circ f = h \circ f \implies g = h$.
 | 
							$g \circ f = h \circ f \implies g = h$.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		\item[\star] Let $f: X \to Y$ be a function where for any set $Z$ and functions $g: Z \to X$ and $h: Z \to X$,
 | 
							\item[$\star$] Let $f: X \to Y$ be a function where for any set $Z$ and functions $g: Z \to X$ and $h: Z \to X$,
 | 
				
			||||||
		$f \circ g = f \circ h \implies g = h$. Show that $f$ is injective.
 | 
							$f \circ g = f \circ h \implies g = h$. Show that $f$ is injective.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		\item[\star] Let $f: X \to Y$ be a function where for any set $W$ and functions $g: Y \to W$ and $h: Y \to W$,
 | 
							\item[$\star$] Let $f: X \to Y$ be a function where for any set $W$ and functions $g: Y \to W$ and $h: Y \to W$,
 | 
				
			||||||
		$g \circ f = h \circ f \implies g = h$. Show f is surjective.
 | 
							$g \circ f = h \circ f \implies g = h$. Show f is surjective.
 | 
				
			||||||
	\end{itemize}
 | 
						\end{itemize}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,7 +1,7 @@
 | 
				
			|||||||
# ORMC Handouts
 | 
					# ORMC Handouts
 | 
				
			||||||
 | 
					
 | 
				
			||||||
This repository contains all the handouts I've written for the [ORMC](https://circles.math.ucla.edu/circles/). \
 | 
					This repository contains all the handouts I've written for the [ORMC](https://circles.math.ucla.edu/circles/). \
 | 
				
			||||||
You can find the latest PDFs [here](https://nc.betalupi.com/s/ormc-handouts).
 | 
					You can find the latest PDFs [here](https://static.betalupi.com/ormc).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
**For my students:** Handouts will appear here a few days before class. Please don't look at them (or their solutions) beforehand, that spoils all the fun!
 | 
					**For my students:** Handouts will appear here a few days before class. Please don't look at them (or their solutions) beforehand, that spoils all the fun!
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -21,7 +21,7 @@ Grade levels are estimates.
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
## 🛠️ Building these Handouts
 | 
					## 🛠️ Building these Handouts
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Automatic builds are [here](https://nc.betalupi.com/s/ormc-handouts), if you just want the PDFs.
 | 
					Automatic builds are [here](https://static.betalupi.com/ormc), if you just want the PDFs.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
If you want to edit these files, you'll need to download a custom document class. \
 | 
					If you want to edit these files, you'll need to download a custom document class. \
 | 
				
			||||||
To compile one handout, do the following:
 | 
					To compile one handout, do the following:
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										128
									
								
								build.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										128
									
								
								build.sh
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,128 @@
 | 
				
			|||||||
 | 
					#!/usr/bin/env bash
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# This script builds every document in this repo,
 | 
				
			||||||
 | 
					# (handout and solutions, if they exist), and creates
 | 
				
			||||||
 | 
					# a zip of all resulting files.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Where we're running this script
 | 
				
			||||||
 | 
					run_dir=$(pwd)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Output files
 | 
				
			||||||
 | 
					target_dir="${run_dir}/output"
 | 
				
			||||||
 | 
					target_zip="${run_dir}/output.zip"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Clean up previous build
 | 
				
			||||||
 | 
					rm -drf "${target_dir}"
 | 
				
			||||||
 | 
					rm -f "${target_zip}"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Build one document.
 | 
				
			||||||
 | 
					# Args: <target_dir> <job_name> <doc_dir> <main_file>
 | 
				
			||||||
 | 
					# target_dir: move output pdf to this directory
 | 
				
			||||||
 | 
					# job_name: name of this document. Output is saved as job_name.pdf
 | 
				
			||||||
 | 
					# doc_dir: cd here before building.
 | 
				
			||||||
 | 
					# main_file: build this tex file. Usually main.tex
 | 
				
			||||||
 | 
					function build() {
 | 
				
			||||||
 | 
						local target_dir="${1}"
 | 
				
			||||||
 | 
						local job_name="${2}"
 | 
				
			||||||
 | 
						local doc_dir="${3}"
 | 
				
			||||||
 | 
						local main_file="${4}"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						echo "|> Building ${job_name}..."
 | 
				
			||||||
 | 
						cd "${doc_dir}"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						# Build handout
 | 
				
			||||||
 | 
						echo "\\def\\argNoSolutions{1}\\input{${main_file}}" | \
 | 
				
			||||||
 | 
							tectonic \
 | 
				
			||||||
 | 
								--outfmt pdf \
 | 
				
			||||||
 | 
								--chatter minimal \
 | 
				
			||||||
 | 
								-
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						stat=$?
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if [[ $stat == 0 ]]; then
 | 
				
			||||||
 | 
							mkdir -p "${target_dir}"
 | 
				
			||||||
 | 
							mv texput.pdf "${target_dir}/${job_name}.pdf"
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							rmdir --ignore-fail-on-non-empty "${target_dir}"
 | 
				
			||||||
 | 
							rm -f texput.pdf
 | 
				
			||||||
 | 
							echo "|> Handout build failed"
 | 
				
			||||||
 | 
							echo ""
 | 
				
			||||||
 | 
						fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						# Build solutions
 | 
				
			||||||
 | 
						echo "\\def\\argYesSolutions{1}\\input{${main_file}}" | \
 | 
				
			||||||
 | 
							tectonic \
 | 
				
			||||||
 | 
								--outfmt pdf \
 | 
				
			||||||
 | 
								--chatter minimal \
 | 
				
			||||||
 | 
								-
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						stat=$?
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if [[ $stat == 0 ]]; then
 | 
				
			||||||
 | 
							mkdir -p "${target_dir}"
 | 
				
			||||||
 | 
							mv texput.pdf "${target_dir}/${job_name}.sols.pdf"
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							rmdir --ignore-fail-on-non-empty "${target_dir}"
 | 
				
			||||||
 | 
							rm -f texput.pdf
 | 
				
			||||||
 | 
							echo "|> Solution build failed"
 | 
				
			||||||
 | 
						fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						# Clean up if files contents are identical
 | 
				
			||||||
 | 
						if cmp --silent -- "${target_dir}/${job_name}.sols.pdf" "${target_dir}/${job_name}.pdf"; then
 | 
				
			||||||
 | 
							echo "|> Versions identical, removing ${job_name}.sols.pdf"
 | 
				
			||||||
 | 
							rm "${target_dir}/${job_name}.sols.pdf"
 | 
				
			||||||
 | 
						fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						echo ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						cd "${run_dir}"
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					for d in "${run_dir}/Misc/Warm-Ups"/*.tex ; do
 | 
				
			||||||
 | 
						file="$(basename "${d}")"
 | 
				
			||||||
 | 
						build \
 | 
				
			||||||
 | 
							"${target_dir}/Warm-Ups" \
 | 
				
			||||||
 | 
							"${file%.*}" \
 | 
				
			||||||
 | 
							"${run_dir}/Misc/Warm-Ups" \
 | 
				
			||||||
 | 
							"${file}"
 | 
				
			||||||
 | 
					done
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					for d in "${run_dir}/Advanced"/*/ ; do
 | 
				
			||||||
 | 
						doc_dir=$(realpath "${d}")
 | 
				
			||||||
 | 
						job_name="$(basename "${doc_dir}")"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						build \
 | 
				
			||||||
 | 
							"${target_dir}/Advanced" \
 | 
				
			||||||
 | 
							"${job_name}" \
 | 
				
			||||||
 | 
							"${doc_dir}" \
 | 
				
			||||||
 | 
							"main.tex"
 | 
				
			||||||
 | 
					done
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					for d in "${run_dir}/Intermediate"/*/ ; do
 | 
				
			||||||
 | 
						doc_dir=$(realpath "${d}")
 | 
				
			||||||
 | 
						job_name="$(basename "${doc_dir}")"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						build \
 | 
				
			||||||
 | 
							"${target_dir}/Intermediate" \
 | 
				
			||||||
 | 
							"${job_name}" \
 | 
				
			||||||
 | 
							"${doc_dir}" \
 | 
				
			||||||
 | 
							"main.tex"
 | 
				
			||||||
 | 
					done
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# cd so paths in zip are relative
 | 
				
			||||||
 | 
					cd "${target_dir}"
 | 
				
			||||||
 | 
					zip -FSr "${target_zip}" .
 | 
				
			||||||
							
								
								
									
										28
									
								
								resources/scripts/Jenkinsfile
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										28
									
								
								resources/scripts/Jenkinsfile
									
									
									
									
										vendored
									
									
								
							@@ -1,28 +0,0 @@
 | 
				
			|||||||
pipeline {
 | 
					 | 
				
			||||||
	agent none
 | 
					 | 
				
			||||||
	environment {
 | 
					 | 
				
			||||||
		NC_CRED	= credentials("nc-jenkins-cred")
 | 
					 | 
				
			||||||
		NO_TEST = true
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	stages {
 | 
					 | 
				
			||||||
		stage("Build") {
 | 
					 | 
				
			||||||
			agent {
 | 
					 | 
				
			||||||
				docker {
 | 
					 | 
				
			||||||
					image "git.betalupi.com/mark/latex:latest"
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			steps {
 | 
					 | 
				
			||||||
				// Keep these in one "sh" directive.
 | 
					 | 
				
			||||||
				// Todo: create setup files so we don't
 | 
					 | 
				
			||||||
				// have to pip install manually here.
 | 
					 | 
				
			||||||
				// Maybe integrate python packages into the docker container?
 | 
					 | 
				
			||||||
				sh '''
 | 
					 | 
				
			||||||
					python -m venv venv
 | 
					 | 
				
			||||||
					source venv/bin/activate
 | 
					 | 
				
			||||||
					pip install tomli webdavclient3
 | 
					 | 
				
			||||||
					python resources/scripts/build.py
 | 
					 | 
				
			||||||
				'''
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -1,155 +0,0 @@
 | 
				
			|||||||
# Build script for CI.
 | 
					 | 
				
			||||||
# This file is run from the root of the repository
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import os
 | 
					 | 
				
			||||||
import tomli
 | 
					 | 
				
			||||||
from pathlib import Path
 | 
					 | 
				
			||||||
import shutil
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
from webdav3.client import Client
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import helpers.tex as tex
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
conf_path = "resources/scripts/build.toml"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# Prepare envvars
 | 
					 | 
				
			||||||
e = os.environ.copy()
 | 
					 | 
				
			||||||
e["TEXINPUTS"] = f"::/usr/share/texmf-dist/tex//"
 | 
					 | 
				
			||||||
print(Path.cwd())
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# If true, rebuild everything
 | 
					 | 
				
			||||||
# without checking for changes.
 | 
					 | 
				
			||||||
# Currently unused.
 | 
					 | 
				
			||||||
if "FORCE_ALL" in e:
 | 
					 | 
				
			||||||
	force_all = e["FORCE_ALL"] == "true"
 | 
					 | 
				
			||||||
else:
 | 
					 | 
				
			||||||
	force_all = False
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
if "NO_TEST" in e:
 | 
					 | 
				
			||||||
	test = e["NO_TEST"] == "false"
 | 
					 | 
				
			||||||
else:
 | 
					 | 
				
			||||||
	test = True
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# Used only for debug
 | 
					 | 
				
			||||||
class FakeClient:
 | 
					 | 
				
			||||||
	def __init__(self):
 | 
					 | 
				
			||||||
		pass
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	def mkdir(self, path):
 | 
					 | 
				
			||||||
		print(f"[Dry run] Making dir {path}")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	def upload_sync(self, local_path, remote_path):
 | 
					 | 
				
			||||||
		print(f"[Dry run] Synced {local_path} to {remote_path}")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	def clean(self, path):
 | 
					 | 
				
			||||||
		print(f"[Dry run] Cleaning {path}")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# Load configuration
 | 
					 | 
				
			||||||
with open(conf_path, mode="rb") as fp:
 | 
					 | 
				
			||||||
	config = tomli.load(fp)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# Prepare directories
 | 
					 | 
				
			||||||
builddir = Path().absolute() / config["core"]["build_dir"]
 | 
					 | 
				
			||||||
output = Path().absolute() / config["core"]["output_dir"]
 | 
					 | 
				
			||||||
output.mkdir(parents = True, exist_ok = True)
 | 
					 | 
				
			||||||
builddir.mkdir(parents = True, exist_ok = True)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
if not test:
 | 
					 | 
				
			||||||
	# Connect to webdav
 | 
					 | 
				
			||||||
	client = Client({
 | 
					 | 
				
			||||||
		"webdav_login": e["NC_CRED_USR"],
 | 
					 | 
				
			||||||
		"webdav_password": e["NC_CRED_PSW"],
 | 
					 | 
				
			||||||
		"webdav_hostname": e["DAV_HOSTNAME"],	# https://host:port
 | 
					 | 
				
			||||||
		"webdav_root": e["DAV_ROOT"]			# the rest of the url
 | 
					 | 
				
			||||||
		# client.list() will break if we do not seperate the hostname
 | 
					 | 
				
			||||||
		# and the root path.
 | 
					 | 
				
			||||||
	})
 | 
					 | 
				
			||||||
else:
 | 
					 | 
				
			||||||
	client = FakeClient()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def upload_dir(local_path: Path):
 | 
					 | 
				
			||||||
	for p in local_path.rglob("*"):
 | 
					 | 
				
			||||||
		r = p.relative_to(output)
 | 
					 | 
				
			||||||
		if p.is_dir():
 | 
					 | 
				
			||||||
			client.mkdir(str(r))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		elif p.is_file():
 | 
					 | 
				
			||||||
			client.upload_sync(  # type: ignore
 | 
					 | 
				
			||||||
				remote_path = str(r),
 | 
					 | 
				
			||||||
				local_path = p
 | 
					 | 
				
			||||||
			)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# Print envvars for debug
 | 
					 | 
				
			||||||
#print(e)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
for i, item in enumerate(config["dir-of-dirs"]):
 | 
					 | 
				
			||||||
	p = Path(item["path"])
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	for s in p.iterdir():
 | 
					 | 
				
			||||||
		# s: path to directory,
 | 
					 | 
				
			||||||
		# # relative to repo root
 | 
					 | 
				
			||||||
		if not s.is_dir():
 | 
					 | 
				
			||||||
			continue
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		print(f"Building {s}/main.tex")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		# Make pdf
 | 
					 | 
				
			||||||
		pdf_nosolutions = tex.build(
 | 
					 | 
				
			||||||
			s,
 | 
					 | 
				
			||||||
			mainfile = "main.tex",
 | 
					 | 
				
			||||||
			jobname = f"{i}-nosols",
 | 
					 | 
				
			||||||
			build_dir = builddir,
 | 
					 | 
				
			||||||
			solutions = False,
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			env = e,
 | 
					 | 
				
			||||||
			test = test
 | 
					 | 
				
			||||||
		)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		pdf_solutions = tex.build(
 | 
					 | 
				
			||||||
			s,
 | 
					 | 
				
			||||||
			mainfile = "main.tex",
 | 
					 | 
				
			||||||
			jobname = f"{i}-sols",
 | 
					 | 
				
			||||||
			build_dir = builddir,
 | 
					 | 
				
			||||||
			solutions = True,
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			env = e,
 | 
					 | 
				
			||||||
			test = test
 | 
					 | 
				
			||||||
		)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		target_dir = output / s.parent
 | 
					 | 
				
			||||||
		target_dir.mkdir(parents = True, exist_ok = True)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		shutil.copy(
 | 
					 | 
				
			||||||
			pdf_nosolutions,
 | 
					 | 
				
			||||||
			target_dir / (s.stem + ".pdf")
 | 
					 | 
				
			||||||
		)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		shutil.copy(
 | 
					 | 
				
			||||||
			pdf_solutions,
 | 
					 | 
				
			||||||
			target_dir / (s.stem + ".sols.pdf")
 | 
					 | 
				
			||||||
		)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# TODO: this breaks when the output directory is empty.
 | 
					 | 
				
			||||||
# Fix it eventually.
 | 
					 | 
				
			||||||
if not test:
 | 
					 | 
				
			||||||
	# Delete old files
 | 
					 | 
				
			||||||
	for i in client.list():
 | 
					 | 
				
			||||||
		if i.endswith("/"):
 | 
					 | 
				
			||||||
			i = i[:-1]
 | 
					 | 
				
			||||||
		client.clean(i)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
upload_dir(output)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# Remove output files so they don't persist
 | 
					 | 
				
			||||||
# shutil.rmtree(output)
 | 
					 | 
				
			||||||
# Shouldn't be necessary if you tell
 | 
					 | 
				
			||||||
# jenkins to "clean before checkout."
 | 
					 | 
				
			||||||
@@ -1,12 +0,0 @@
 | 
				
			|||||||
# All paths are relative to the root of this repository.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
[core]
 | 
					 | 
				
			||||||
build_dir = "_build"
 | 
					 | 
				
			||||||
output_dir = "_output"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
[[dir-of-dirs]]
 | 
					 | 
				
			||||||
path = "Advanced"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
[[dir-of-dirs]]
 | 
					 | 
				
			||||||
path = "Intermediate"
 | 
					 | 
				
			||||||
@@ -1,60 +0,0 @@
 | 
				
			|||||||
from pathlib import Path
 | 
					 | 
				
			||||||
import subprocess
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def build(
 | 
					 | 
				
			||||||
		path: Path,
 | 
					 | 
				
			||||||
		*,
 | 
					 | 
				
			||||||
		solutions: bool = True,
 | 
					 | 
				
			||||||
		mainfile: str = "main.tex",
 | 
					 | 
				
			||||||
		jobname: str = "main",
 | 
					 | 
				
			||||||
		build_dir: Path = Path("build"),
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		test = False,
 | 
					 | 
				
			||||||
		env: dict = {},
 | 
					 | 
				
			||||||
	) -> Path:
 | 
					 | 
				
			||||||
	"""
 | 
					 | 
				
			||||||
	Build a directory using XeTeX.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	Args:
 | 
					 | 
				
			||||||
		path (Path): directory to build
 | 
					 | 
				
			||||||
		solutions (bool, optional): Create a handout with solutions? Defaults to True.
 | 
					 | 
				
			||||||
		mainfile (str, optional): Path to main TeX file, relative to path. Defaults to "main.tex".
 | 
					 | 
				
			||||||
		jobname (str, optional): TeX job name. Defaults to "main".
 | 
					 | 
				
			||||||
		build_dir (Path, optional): Where to place build files. Defaults to Path("build").
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		test (bool, optional): If true, dry run. Defaults to False.
 | 
					 | 
				
			||||||
		env (dict): Dictionary of environment variables.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	Returns:
 | 
					 | 
				
			||||||
		Path: Absolute path to output pdf.
 | 
					 | 
				
			||||||
	"""
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	# Make temporary file for TeX build arg hack
 | 
					 | 
				
			||||||
	if solutions:
 | 
					 | 
				
			||||||
		with (build_dir/"tmp.tex").open("w") as f:
 | 
					 | 
				
			||||||
			f.write("\\def\\argYesSolutions{1}\\input{" + mainfile + "}")
 | 
					 | 
				
			||||||
	else:
 | 
					 | 
				
			||||||
		with (build_dir/"tmp.tex").open("w") as f:
 | 
					 | 
				
			||||||
			f.write("\\def\\argNoSolutions{1}\\input{" + mainfile + "}")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	cmd = subprocess.run([
 | 
					 | 
				
			||||||
			"latexmk",
 | 
					 | 
				
			||||||
			"-interaction=nonstopmode",
 | 
					 | 
				
			||||||
			"-file-line-error",
 | 
					 | 
				
			||||||
			f"-outdir={build_dir}",
 | 
					 | 
				
			||||||
			"-xelatex",
 | 
					 | 
				
			||||||
			f"-jobname={jobname}",
 | 
					 | 
				
			||||||
			build_dir/"tmp.tex"
 | 
					 | 
				
			||||||
		],
 | 
					 | 
				
			||||||
		cwd = path,
 | 
					 | 
				
			||||||
		env = env,
 | 
					 | 
				
			||||||
		stdout = None if test else subprocess.DEVNULL,
 | 
					 | 
				
			||||||
		stderr = None if test else subprocess.DEVNULL
 | 
					 | 
				
			||||||
	)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	assert cmd.returncode == 0
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	# Remove tmp file
 | 
					 | 
				
			||||||
	(build_dir / "tmp.tex").unlink()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return build_dir / f"{jobname}.pdf"
 | 
					 | 
				
			||||||
		Reference in New Issue
	
	Block a user