91 lines
3.1 KiB
Python
91 lines
3.1 KiB
Python
#!/usr/bin/python3
|
|
import warnings
|
|
|
|
import yaml
|
|
from typing import List
|
|
|
|
from config_loader import ROOT, CURRENT_COURSE_ROOT, CURRENT_COURSE_SYMLINK, CURRENT_COURSE_WATCH_FILE, COURSE_IGNORE_FILE, \
|
|
COURSE_INFO_FILE_NAME, FALLBACK_COURSE_INFO_FILE
|
|
from notes import Notes
|
|
from links import Links
|
|
from utils import merge_dictionaries
|
|
from exercises import Exercises
|
|
|
|
|
|
class Course:
|
|
def __init__(self, path):
|
|
self.path = path
|
|
self.name = path.stem
|
|
if (path / COURSE_INFO_FILE_NAME).is_file():
|
|
self.info = yaml.safe_load((path / COURSE_INFO_FILE_NAME).open())
|
|
else:
|
|
warnings.warn(f"No course info file found in directory '{path.stem}'. Place a {COURSE_INFO_FILE_NAME} "
|
|
f"file in the directory or add the directory to the course ignore file named"
|
|
f" '{COURSE_IGNORE_FILE}' in your root directory ({ROOT})")
|
|
self.info = {'title': str(path.stem) + ' (unnamed course)'}
|
|
if FALLBACK_COURSE_INFO_FILE.is_file():
|
|
fallback_file = yaml.safe_load(FALLBACK_COURSE_INFO_FILE.open())
|
|
else:
|
|
warnings.warn(f"No fallback course info file found. Program might crash if your provided info files do not"
|
|
f"have the correct file format or are missing specified values. Provide the fallback course"
|
|
f"file at {FALLBACK_COURSE_INFO_FILE}.")
|
|
fallback_file = {}
|
|
self.info = merge_dictionaries(self.info, fallback_file)
|
|
self._notes = None
|
|
self._links = None
|
|
self._exercises = None
|
|
|
|
@property
|
|
def links(self) -> Links:
|
|
if not self._links:
|
|
self._links = Links(self)
|
|
return self._links
|
|
|
|
@property
|
|
def notes(self) -> Notes:
|
|
if not self._notes:
|
|
self._notes = Notes(self)
|
|
return self._notes
|
|
|
|
@property
|
|
def exercises(self) -> Exercises:
|
|
if not self._exercises:
|
|
self._exercises = Exercises(self)
|
|
return self._exercises
|
|
|
|
def __eq__(self, other):
|
|
if other is None:
|
|
return False
|
|
return self.path == other.path
|
|
|
|
|
|
def ignored_courses() -> List[Course]:
|
|
if (ROOT / COURSE_IGNORE_FILE).is_file():
|
|
with open(ROOT / COURSE_IGNORE_FILE) as ignore:
|
|
lines = ignore.readlines()
|
|
paths = []
|
|
for line in lines:
|
|
paths.append(ROOT / line.strip())
|
|
return paths
|
|
return []
|
|
|
|
|
|
def read_files() -> List[Course]:
|
|
course_directories = [x for x in ROOT.iterdir() if x.is_dir() and x not in ignored_courses()]
|
|
_courses = [Course(path) for path in course_directories]
|
|
return sorted(_courses, key=lambda c: c.name)
|
|
|
|
|
|
class Courses(list):
|
|
def __init__(self):
|
|
list.__init__(self, read_files())
|
|
|
|
@property
|
|
def current(self) -> Course:
|
|
return Course(CURRENT_COURSE_ROOT.resolve())
|
|
|
|
@current.setter
|
|
def current(self, course):
|
|
CURRENT_COURSE_SYMLINK.unlink()
|
|
CURRENT_COURSE_SYMLINK.symlink_to(course.path)
|
|
CURRENT_COURSE_WATCH_FILE.write_text('{}\n'.format(course.info['short']))
|