mirror of
https://github.com/RGBCube/CSAssignments
synced 2025-07-27 05:57:44 +00:00
Oops
This commit is contained in:
parent
df3ebcd560
commit
57f4be66d2
20 changed files with 322 additions and 1681 deletions
3
interactive_runner/__init__.py
Normal file
3
interactive_runner/__init__.py
Normal file
|
@ -0,0 +1,3 @@
|
|||
from .assignment import *
|
||||
from .language import *
|
||||
from .sources import *
|
24
interactive_runner/__main__.py
Normal file
24
interactive_runner/__main__.py
Normal file
|
@ -0,0 +1,24 @@
|
|||
import interactive_runner as lib
|
||||
|
||||
s = lib.Sources()
|
||||
for l in s.languages.values():
|
||||
print("lname",l.name)
|
||||
print("lsname",l.styled_name)
|
||||
print("ldesc",l.description)
|
||||
print("lbc",l._build_command)
|
||||
print("ldni",l.check_dependencies_installed())
|
||||
print("lisc",l.is_compiled)
|
||||
print("lrcmd",l._run_command)
|
||||
print()
|
||||
for a in l.assignments.values():
|
||||
print("alang",a.language)
|
||||
print("aname",a.name)
|
||||
print("agivend",a.given_date)
|
||||
print("adesc",a.description)
|
||||
print("adirs",a.directions)
|
||||
try:
|
||||
a.run()
|
||||
except Exception as e:
|
||||
print("errrun",e)
|
||||
print()
|
||||
|
85
interactive_runner/assignment.py
Normal file
85
interactive_runner/assignment.py
Normal file
|
@ -0,0 +1,85 @@
|
|||
from __future__ import annotations
|
||||
|
||||
__all__ = ("Assignment",)
|
||||
|
||||
from functools import cached_property
|
||||
from typing import TypedDict, TYPE_CHECKING
|
||||
from tomllib import loads as decode_toml
|
||||
from os import system as cmd
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from .language import Language
|
||||
|
||||
AssignmentConfig = TypedDict(
|
||||
"AssignmentConfig",
|
||||
{
|
||||
"name": str,
|
||||
"given-date": str,
|
||||
"main-file": str,
|
||||
"description": str,
|
||||
"directions": str,
|
||||
}
|
||||
)
|
||||
|
||||
class Assignment:
|
||||
__config: AssignmentConfig
|
||||
language: Language
|
||||
name: str
|
||||
given_date: str
|
||||
__main_file: str
|
||||
description: str
|
||||
directions: str
|
||||
|
||||
def __init__(self, directory: Path, language: Language) -> None:
|
||||
self.__directory = directory
|
||||
self.language = language
|
||||
|
||||
@cached_property
|
||||
def __config(self) -> AssignmentConfig:
|
||||
return decode_toml((self.__directory / "assignment.toml").read_text())
|
||||
|
||||
def refresh(self) -> None:
|
||||
del self.__config
|
||||
|
||||
@property
|
||||
def name(self) -> str:
|
||||
return self.__config["name"]
|
||||
|
||||
@property
|
||||
def given_date(self) -> str:
|
||||
return self.__config["given-date"]
|
||||
|
||||
@property
|
||||
def __main_file(self) -> Path:
|
||||
return self.__directory / self.__config["main-file"]
|
||||
|
||||
@property
|
||||
def description(self) -> str:
|
||||
return self.__config["description"]
|
||||
|
||||
@property
|
||||
def directions(self) -> str:
|
||||
return self.__config["directions"]
|
||||
|
||||
def compile(self, *, quiet: bool) -> int | None:
|
||||
if missing := self.language.check_dependencies_installed():
|
||||
raise ValueError(f"Needed depencencies are not installed: {', '.join(missing)}")
|
||||
|
||||
if not self.language.is_compiled:
|
||||
return None
|
||||
|
||||
return cmd(self.language._build_command.format(
|
||||
**{
|
||||
"out-file": self.__directory / "compiled.out",
|
||||
"main-file": self.__main_file.absolute(),
|
||||
}
|
||||
) +
|
||||
(QUIET_SUFFIX if quiet else "")
|
||||
)
|
||||
|
||||
def run(self) -> int:
|
||||
if self.language.is_compiled and not (self.__directory / "compiled.out").exists():
|
||||
self.compile(quiet=True)
|
||||
|
||||
return cmd(self.language._run_command.format((self.__directory / "compiled.out").absolute() if self.language.is_compiled else self.__main_file.absolute()))
|
||||
|
10
interactive_runner/consts.py
Normal file
10
interactive_runner/consts.py
Normal file
|
@ -0,0 +1,10 @@
|
|||
__all__ = ("ROOT", "IS_WINDOWS", "QUIET_SUFFIX", "CHECK_COMMAND_EXISTS", "OS_KEY")
|
||||
|
||||
from os import name as os_name
|
||||
from pathlib import Path
|
||||
|
||||
ROOT = Path(__file__).parent.parent
|
||||
IS_WINDOWS = os_name == "nt"
|
||||
QUIET_SUFFIX = " | Out-Null" if IS_WINDOWS else " > /dev/null"
|
||||
CHECK_COMMAND_EXISTS = ("Get-Command {}" if IS_WINDOWS else "command -v {}") + QUIET_SUFFIX
|
||||
OS_KEY = "windows" if IS_WINDOWS else "unix"
|
135
interactive_runner/language.py
Normal file
135
interactive_runner/language.py
Normal file
|
@ -0,0 +1,135 @@
|
|||
from __future__ import annotations
|
||||
|
||||
__all__ = ("Language",)
|
||||
|
||||
from .assignment import Assignment
|
||||
from .consts import OS_KEY, CHECK_COMMAND_EXISTS
|
||||
from typing import TYPE_CHECKING, TypedDict
|
||||
from tomllib import loads as decode_toml
|
||||
from chalky import hex
|
||||
from functools import cached_property
|
||||
from os import system as cmd
|
||||
from chalky.shortcuts.sty import bold
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from pathlib import Path
|
||||
|
||||
LanguageConfig = TypedDict(
|
||||
"LanguageConfig",
|
||||
{
|
||||
"name": str,
|
||||
"descripton": str,
|
||||
"colors": TypedDict(
|
||||
"ColorConfig",
|
||||
{
|
||||
"foregroud": int,
|
||||
"background": int,
|
||||
}
|
||||
),
|
||||
"build": None | TypedDict(
|
||||
"BuildConfig",
|
||||
{
|
||||
"common": str | None,
|
||||
"unix": str | None,
|
||||
"windows": str | None,
|
||||
}
|
||||
),
|
||||
"run": TypedDict(
|
||||
"RunConfig",
|
||||
{
|
||||
"common": str | None,
|
||||
"unix": str | None,
|
||||
"windows": str | None,
|
||||
}
|
||||
),
|
||||
"dependencies": None | TypedDict(
|
||||
"DependencyConfig",
|
||||
{
|
||||
"common": list[str] | None,
|
||||
"unix": list[str] | None,
|
||||
"windows": list[str] | None,
|
||||
}
|
||||
),
|
||||
}
|
||||
)
|
||||
|
||||
class Language:
|
||||
__directory: Path
|
||||
__config: LanguageConfig
|
||||
name: str
|
||||
styled_name: str
|
||||
description: str
|
||||
__dependencies: list[str] | None
|
||||
_build_command: str | None
|
||||
is_compiled: bool
|
||||
_run_command: str
|
||||
assignments: dict[str, Assignment]
|
||||
|
||||
def __init__(self, directory: Path) -> None:
|
||||
self.__directory = directory
|
||||
|
||||
@cached_property
|
||||
def __config(self) -> LanguageConfig:
|
||||
return decode_toml((self.__directory / "language.toml").read_text())
|
||||
|
||||
def refresh(self) -> None:
|
||||
del self.__config
|
||||
del self.assignments
|
||||
|
||||
@property
|
||||
def name(self) -> str:
|
||||
return self.__config["name"]
|
||||
|
||||
@property
|
||||
def styled_name(self) -> str:
|
||||
colors = self.__config["colors"]
|
||||
# hack
|
||||
return hex(colors["foreground"]) & hex(colors["background"], background=True) | self.name
|
||||
|
||||
@property
|
||||
def description(self) -> str:
|
||||
return self.__config["description"]
|
||||
|
||||
@property
|
||||
def __dependencies(self) -> list[str] | None:
|
||||
dependencies = self.__config.get("dependencies", {})
|
||||
return dependencies.get("common", dependencies.get(OS_KEY))
|
||||
|
||||
def check_dependencies_installed(self) -> list[str]:
|
||||
if self.__dependencies is None:
|
||||
return []
|
||||
|
||||
not_installed = []
|
||||
for dependency in self.__dependencies:
|
||||
exit = cmd(CHECK_COMMAND_EXISTS.format(dependency))
|
||||
|
||||
if exit:
|
||||
not_installed.append(dependency)
|
||||
|
||||
return not_installed
|
||||
|
||||
@property
|
||||
def _build_command(self) -> str | None:
|
||||
build = self.__config.get("build", {})
|
||||
return build.get("common", build.get(OS_KEY))
|
||||
|
||||
@property
|
||||
def is_compiled(self) -> bool:
|
||||
return bool(self._build_command)
|
||||
|
||||
@property
|
||||
def _run_command(self) -> str:
|
||||
run = self.__config["run"]
|
||||
return run.get("common", run.get(OS_KEY))
|
||||
|
||||
@cached_property
|
||||
def assignments(self) -> dict[str, Assignment]:
|
||||
assignments = {}
|
||||
|
||||
for assignment_directory in self.__directory.iterdir():
|
||||
if not assignment_directory.is_dir():
|
||||
continue
|
||||
|
||||
assignments[assignment_directory.name] = Assignment(assignment_directory, self)
|
||||
|
||||
return assignments
|
33
interactive_runner/sources.py
Normal file
33
interactive_runner/sources.py
Normal file
|
@ -0,0 +1,33 @@
|
|||
from __future__ import annotations
|
||||
|
||||
__all__ = ("Sources",)
|
||||
|
||||
from .language import Language
|
||||
from .consts import ROOT
|
||||
from functools import cached_property
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from pathlib import Path
|
||||
|
||||
class Sources:
|
||||
__directory: Path
|
||||
languages: dict[str, Language]
|
||||
|
||||
def __init__(self) -> None:
|
||||
self.__directory = ROOT / "sources"
|
||||
|
||||
@cached_property
|
||||
def languages(self) -> dict[str, Language]:
|
||||
languages = {}
|
||||
|
||||
for language_directory in self.__directory.iterdir():
|
||||
if not language_directory.is_dir():
|
||||
continue
|
||||
|
||||
languages[language_directory.name] = Language(language_directory)
|
||||
|
||||
return languages
|
||||
|
||||
def refresh(self) -> None:
|
||||
del self.languages
|
Loading…
Add table
Add a link
Reference in a new issue