mirror of
https://github.com/decompme/decomp.me.git
synced 2025-12-19 20:09:47 -06:00
Migrate from poetry/black to uv/ruff (#1673)
* Migrate from poetry/black to uv/ruff * fixes * path change * path pt 2 * ah * mkst tweaks (#1674) * mkst tweaks * tweaks++ * doh * tweak harder --------- Co-authored-by: Mark Street <22226349+mkst@users.noreply.github.com>
This commit is contained in:
12
.github/workflows/chores.yaml
vendored
12
.github/workflows/chores.yaml
vendored
@@ -19,13 +19,13 @@ jobs:
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: "3.11"
|
||||
python-version: "3.12"
|
||||
|
||||
- name: Install Poetry
|
||||
run: pip install poetry==2.2.0
|
||||
- name: Install uv
|
||||
run: pip install uv
|
||||
|
||||
- name: Update m2c & asm-differ
|
||||
run: cd backend && poetry update m2c asm-differ
|
||||
run: cd backend && uv pip install --upgrade m2c asm-differ
|
||||
|
||||
- name: Check for changes
|
||||
run: |
|
||||
@@ -37,8 +37,8 @@ jobs:
|
||||
- name: Commit changes
|
||||
uses: peter-evans/create-pull-request@v6
|
||||
with:
|
||||
commit-message: "🤖 (chore): bump m2c & asm-differ to latest"
|
||||
title: "🤖 (chore): bump m2c & asm-differ to latest"
|
||||
commit-message: "🤖 (chore): bump m2c / asm-differ to latest"
|
||||
title: "🤖 (chore): bump m2c / asm-differ to latest"
|
||||
branch: "update-m2c-asm-differ"
|
||||
delete-branch: true
|
||||
committer: "GitHub Actions <actions@github.com>"
|
||||
|
||||
51
.github/workflows/ci.yml
vendored
51
.github/workflows/ci.yml
vendored
@@ -18,10 +18,12 @@ jobs:
|
||||
run: |-
|
||||
sudo sysctl -w kernel.apparmor_restrict_unprivileged_unconfined=0
|
||||
sudo sysctl -w kernel.apparmor_restrict_unprivileged_userns=0
|
||||
mkdir -p sandbox && chmod 777 sandbox
|
||||
mkdir -p local_files && chmod 777 local_files
|
||||
mkdir -p compilers && chmod 777 compilers
|
||||
mkdir -p libraries && chmod 777 libraries
|
||||
# NOTE: CI does not run as 'ubuntu' user
|
||||
export USER_1000=$(getent passwd 1000 | cut -d: -f1)
|
||||
for dir in backend/.venv sandbox local_files compilers libraries; do
|
||||
mkdir -p "$dir"
|
||||
sudo chown "${USER_1000}:${USER_1000}" "$dir"
|
||||
done
|
||||
docker run \
|
||||
-v $(pwd):/decomp.me \
|
||||
-v $(pwd)/local_files:/local_files \
|
||||
@@ -42,14 +44,13 @@ jobs:
|
||||
-e USE_SANDBOX_JAIL=on \
|
||||
-e SANDBOX_DISABLE_PROC=true \
|
||||
-e TIMEOUT_SCALE_FACTOR=10 \
|
||||
-e POETRY_VIRTUALENVS_PATH=/backend/virtualenvs \
|
||||
decompme_backend \
|
||||
-c 'cd /decomp.me/backend && \
|
||||
poetry install --no-root && \
|
||||
poetry run compilers/download.py --compilers-dir ${COMPILER_BASE_PATH} && \
|
||||
poetry run libraries/download.py --libraries-dir ${LIBRARY_BASE_PATH} && \
|
||||
uv sync && \
|
||||
uv run compilers/download.py --compilers-dir ${COMPILER_BASE_PATH} && \
|
||||
uv run libraries/download.py --libraries-dir ${LIBRARY_BASE_PATH} && \
|
||||
for r in wine/*.reg; do regedit $r; done && \
|
||||
poetry run python manage.py test'
|
||||
uv run python manage.py test'
|
||||
|
||||
backend_test_docker_prod:
|
||||
name: backend tests (docker prod container)
|
||||
@@ -98,7 +99,7 @@ jobs:
|
||||
decompme_backend \
|
||||
-c '\
|
||||
for r in wine/*.reg; do regedit $r; done && \
|
||||
poetry run python manage.py test'
|
||||
uv run python manage.py test'
|
||||
|
||||
docker_compose_test:
|
||||
name: test docker compose
|
||||
@@ -191,24 +192,34 @@ jobs:
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Install poetry
|
||||
run: pipx install poetry
|
||||
- name: Install uv
|
||||
uses: astral-sh/setup-uv@v4
|
||||
with:
|
||||
version: "latest"
|
||||
- name: Setup Python 3.12
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: "3.12"
|
||||
cache: poetry
|
||||
cache-dependency-path: backend/poetry.lock
|
||||
- run: |-
|
||||
cd backend
|
||||
poetry install --no-root
|
||||
poetry run mypy
|
||||
uv sync
|
||||
uv run mypy
|
||||
|
||||
black:
|
||||
name: black
|
||||
ruff:
|
||||
name: ruff
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: psf/black@stable
|
||||
- name: Install uv
|
||||
uses: astral-sh/setup-uv@v4
|
||||
with:
|
||||
src: "./backend"
|
||||
version: "latest"
|
||||
- name: Setup Python 3.12
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: "3.12"
|
||||
- run: |-
|
||||
cd backend
|
||||
uv sync
|
||||
uv run ruff check .
|
||||
uv run ruff format --check .
|
||||
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -24,3 +24,4 @@ docker.prod.env
|
||||
.vercel
|
||||
send_update.py
|
||||
update.sh
|
||||
.venv/
|
||||
|
||||
22
.vscode/settings.json
vendored
22
.vscode/settings.json
vendored
@@ -1,44 +1,40 @@
|
||||
{
|
||||
"files.trimTrailingWhitespace": true,
|
||||
// eslint
|
||||
"eslint.workingDirectories": [
|
||||
"frontend"
|
||||
],
|
||||
"eslint.workingDirectories": ["frontend"],
|
||||
"eslint.format.enable": true,
|
||||
"[javascript]": {
|
||||
"editor.defaultFormatter": "biomejs.biome",
|
||||
"editor.formatOnSave": true,
|
||||
"editor.formatOnSave": true
|
||||
},
|
||||
"[javascriptreact]": {
|
||||
"editor.defaultFormatter": "biomejs.biome",
|
||||
"editor.formatOnSave": true,
|
||||
"editor.formatOnSave": true
|
||||
},
|
||||
"[typescript]": {
|
||||
"editor.defaultFormatter": "biomejs.biome",
|
||||
"editor.formatOnSave": true,
|
||||
"editor.formatOnSave": true
|
||||
},
|
||||
"[typescriptreact]": {
|
||||
"editor.defaultFormatter": "biomejs.biome",
|
||||
"editor.formatOnSave": true,
|
||||
"editor.formatOnSave": true
|
||||
},
|
||||
// stylelint
|
||||
"[css]": {
|
||||
"editor.defaultFormatter": "stylelint.vscode-stylelint",
|
||||
"editor.formatOnSave": true,
|
||||
"editor.formatOnSave": true
|
||||
},
|
||||
"[scss]": {
|
||||
"editor.defaultFormatter": "stylelint.vscode-stylelint",
|
||||
"editor.formatOnSave": true,
|
||||
"editor.formatOnSave": true
|
||||
},
|
||||
"[python]": {
|
||||
"editor.formatOnSave": true,
|
||||
"editor.defaultFormatter": "ms-python.black-formatter",
|
||||
"editor.defaultFormatter": "charliermarsh.ruff"
|
||||
},
|
||||
"typescript.tsdk": "frontend/node_modules/typescript/lib",
|
||||
"typescript.enablePromptUseWorkspaceTsdk": true,
|
||||
"mypy-type-checker.args": [
|
||||
"--config-file=backend/mypy.ini"
|
||||
],
|
||||
"mypy-type-checker.args": ["--config-file=backend/mypy.ini"],
|
||||
"json.format.enable": false,
|
||||
"json.format.keepLines": true
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
virtualenvs/
|
||||
__pycache__/
|
||||
.mypy_cache/
|
||||
.venv/
|
||||
|
||||
# avoid cache-busting when testing Docker
|
||||
Dockerfile*
|
||||
|
||||
@@ -4,41 +4,33 @@ ENV DEBIAN_FRONTEND=noninteractive
|
||||
|
||||
RUN apt-get update \
|
||||
&& apt-get install -y --no-install-recommends \
|
||||
ca-certificates \
|
||||
curl \
|
||||
python-is-python3 \
|
||||
python3 \
|
||||
python3-pip \
|
||||
python3.12-dev \
|
||||
python3.12-venv \
|
||||
software-properties-common \
|
||||
ca-certificates \
|
||||
curl \
|
||||
git \
|
||||
python-is-python3 \
|
||||
python3 \
|
||||
python3-pip \
|
||||
python3.12-dev \
|
||||
python3.12-venv \
|
||||
software-properties-common \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
RUN curl -sSL https://install.python-poetry.org/ | \
|
||||
POETRY_VERSION=2.2.0 \
|
||||
POETRY_HOME=/etc/poetry \
|
||||
python3.12 -
|
||||
|
||||
ENV POETRY_VIRTUALENVS_PATH=/virtualenvs
|
||||
|
||||
ENV PATH="${PATH}:/etc/poetry/bin"
|
||||
|
||||
RUN curl -LsSf https://astral.sh/uv/install.sh | env UV_INSTALL_DIR="/usr/bin/" sh
|
||||
|
||||
FROM base AS nsjail
|
||||
|
||||
RUN apt-get -y update && apt-get install -y \
|
||||
autoconf \
|
||||
bison \
|
||||
flex \
|
||||
g++ \
|
||||
gcc \
|
||||
git \
|
||||
libnl-route-3-dev \
|
||||
libprotobuf-dev \
|
||||
libtool \
|
||||
make \
|
||||
pkg-config \
|
||||
protobuf-compiler
|
||||
autoconf \
|
||||
bison \
|
||||
flex \
|
||||
g++ \
|
||||
gcc \
|
||||
libnl-route-3-dev \
|
||||
libprotobuf-dev \
|
||||
libtool \
|
||||
make \
|
||||
pkg-config \
|
||||
protobuf-compiler
|
||||
|
||||
RUN git clone "https://github.com/google/nsjail" --recursive --branch 3.4 /nsjail \
|
||||
&& cd /nsjail \
|
||||
@@ -52,31 +44,31 @@ RUN dpkg --add-architecture i386 \
|
||||
&& add-apt-repository -y ppa:stsp-0/dj64 \
|
||||
&& apt-get update \
|
||||
&& apt-get install -y -o APT::Immediate-Configure=false --no-install-recommends \
|
||||
binutils-aarch64-linux-gnu \
|
||||
binutils-arm-none-eabi \
|
||||
binutils-djgpp \
|
||||
binutils-mingw-w64-i686 \
|
||||
binutils-mips-linux-gnu \
|
||||
binutils-powerpc-linux-gnu \
|
||||
binutils-sh-elf \
|
||||
cpp \
|
||||
dj64 \
|
||||
dos2unix \
|
||||
dosemu2 \
|
||||
gcc-mips-linux-gnu \
|
||||
iptables \
|
||||
libarchive-tools \
|
||||
libc6-dev-i386 \
|
||||
libdevmapper1.02.1 \
|
||||
libgpgme11 \
|
||||
libnl-route-3-200 \
|
||||
libprotobuf-dev \
|
||||
libtinfo6 \
|
||||
netcat-traditional \
|
||||
unzip \
|
||||
wget \
|
||||
wine \
|
||||
wine32:i386 \
|
||||
binutils-aarch64-linux-gnu \
|
||||
binutils-arm-none-eabi \
|
||||
binutils-djgpp \
|
||||
binutils-mingw-w64-i686 \
|
||||
binutils-mips-linux-gnu \
|
||||
binutils-powerpc-linux-gnu \
|
||||
binutils-sh-elf \
|
||||
cpp \
|
||||
dj64 \
|
||||
dos2unix \
|
||||
dosemu2 \
|
||||
gcc-mips-linux-gnu \
|
||||
iptables \
|
||||
libarchive-tools \
|
||||
libc6-dev-i386 \
|
||||
libdevmapper1.02.1 \
|
||||
libgpgme11 \
|
||||
libnl-route-3-200 \
|
||||
libprotobuf-dev \
|
||||
libtinfo6 \
|
||||
netcat-traditional \
|
||||
unzip \
|
||||
wget \
|
||||
wine \
|
||||
wine32:i386 \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
RUN wget http://security.ubuntu.com/ubuntu/pool/universe/n/ncurses/libtinfo5_6.3-2ubuntu0.1_amd64.deb \
|
||||
@@ -124,7 +116,6 @@ RUN wineboot --init
|
||||
|
||||
WORKDIR /backend
|
||||
|
||||
ENV POETRY_VIRTUALENVS_PATH=/backend/virtualenvs
|
||||
|
||||
ARG ENABLE_DREAMCAST_SUPPORT
|
||||
ARG ENABLE_GBA_SUPPORT
|
||||
|
||||
@@ -4,92 +4,74 @@ ENV DEBIAN_FRONTEND=noninteractive
|
||||
|
||||
RUN apt-get update \
|
||||
&& apt-get install -y --no-install-recommends \
|
||||
ca-certificates \
|
||||
curl \
|
||||
python-is-python3 \
|
||||
python3 \
|
||||
python3-pip \
|
||||
python3.12-dev \
|
||||
python3.12-venv \
|
||||
software-properties-common \
|
||||
ca-certificates \
|
||||
curl \
|
||||
git \
|
||||
python-is-python3 \
|
||||
python3 \
|
||||
python3-pip \
|
||||
python3.12-dev \
|
||||
python3.12-venv \
|
||||
software-properties-common \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
RUN curl -sSL https://install.python-poetry.org/ | \
|
||||
POETRY_VERSION=2.2.0 \
|
||||
POETRY_HOME=/etc/poetry \
|
||||
python3.12 -
|
||||
|
||||
ENV POETRY_VIRTUALENVS_PATH=/virtualenvs
|
||||
|
||||
ENV PATH="${PATH}:/etc/poetry/bin"
|
||||
|
||||
RUN curl -LsSf https://astral.sh/uv/install.sh | env UV_INSTALL_DIR="/usr/bin/" sh
|
||||
|
||||
FROM base AS nsjail
|
||||
|
||||
RUN apt-get update \
|
||||
&& apt-get install -y --no-install-recommends \
|
||||
autoconf \
|
||||
bison \
|
||||
flex \
|
||||
g++ \
|
||||
gcc \
|
||||
git \
|
||||
libnl-route-3-dev \
|
||||
libprotobuf-dev \
|
||||
libtool \
|
||||
make \
|
||||
pkg-config \
|
||||
protobuf-compiler \
|
||||
autoconf \
|
||||
bison \
|
||||
flex \
|
||||
g++ \
|
||||
gcc \
|
||||
libnl-route-3-dev \
|
||||
libprotobuf-dev \
|
||||
libtool \
|
||||
make \
|
||||
pkg-config \
|
||||
protobuf-compiler \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
RUN git clone "https://github.com/google/nsjail" \
|
||||
--recursive --branch 3.4 /nsjail \
|
||||
--recursive --branch 3.4 /nsjail \
|
||||
&& cd /nsjail \
|
||||
&& make
|
||||
|
||||
|
||||
FROM base AS poetry
|
||||
|
||||
COPY pyproject.toml poetry.lock /backend/
|
||||
|
||||
WORKDIR /backend
|
||||
|
||||
# NOTE: adding "--no-dev" results in "ModuleNotFoundError: No module named 'django_stubs_ext'" error
|
||||
RUN poetry install
|
||||
|
||||
|
||||
FROM base AS dependencies
|
||||
FROM base AS developer
|
||||
|
||||
RUN dpkg --add-architecture i386 \
|
||||
&& add-apt-repository -y ppa:dosemu2/ppa \
|
||||
&& add-apt-repository -y ppa:stsp-0/dj64 \
|
||||
&& apt-get update \
|
||||
&& apt-get install -y -o APT::Immediate-Configure=false --no-install-recommends \
|
||||
binutils-aarch64-linux-gnu \
|
||||
binutils-arm-none-eabi \
|
||||
binutils-djgpp \
|
||||
binutils-mingw-w64-i686 \
|
||||
binutils-mips-linux-gnu \
|
||||
binutils-powerpc-linux-gnu \
|
||||
binutils-sh-elf \
|
||||
cpp \
|
||||
dj64 \
|
||||
dos2unix \
|
||||
dosemu2 \
|
||||
gcc-mips-linux-gnu \
|
||||
iptables \
|
||||
libarchive-tools \
|
||||
libc6-dev-i386 \
|
||||
libdevmapper1.02.1 \
|
||||
libgpgme11 \
|
||||
libnl-route-3-200 \
|
||||
libprotobuf-dev \
|
||||
libtinfo6 \
|
||||
netcat-traditional \
|
||||
unzip \
|
||||
wget \
|
||||
wine \
|
||||
wine32:i386 \
|
||||
binutils-aarch64-linux-gnu \
|
||||
binutils-arm-none-eabi \
|
||||
binutils-djgpp \
|
||||
binutils-mingw-w64-i686 \
|
||||
binutils-mips-linux-gnu \
|
||||
binutils-powerpc-linux-gnu \
|
||||
binutils-sh-elf \
|
||||
cpp \
|
||||
dj64 \
|
||||
dos2unix \
|
||||
dosemu2 \
|
||||
gcc-mips-linux-gnu \
|
||||
iptables \
|
||||
libarchive-tools \
|
||||
libc6-dev-i386 \
|
||||
libdevmapper1.02.1 \
|
||||
libgpgme11 \
|
||||
libnl-route-3-200 \
|
||||
libprotobuf-dev \
|
||||
libtinfo6 \
|
||||
netcat-traditional \
|
||||
unzip \
|
||||
wget \
|
||||
wine \
|
||||
wine32:i386 \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
RUN wget http://security.ubuntu.com/ubuntu/pool/universe/n/ncurses/libtinfo5_6.3-2ubuntu0.1_amd64.deb \
|
||||
@@ -123,13 +105,11 @@ RUN mkdir -p /etc/fonts
|
||||
|
||||
ENV WINEPREFIX=/tmp/wine
|
||||
|
||||
# Ensure /sandbox, wine, and virtualenv dirs have correct ownership
|
||||
# Ensure /sandbox and wine dirs have correct ownership
|
||||
RUN mkdir -p /sandbox \
|
||||
&& chown -R ubuntu:ubuntu /sandbox \
|
||||
&& mkdir -p "${WINEPREFIX}" \
|
||||
&& chown ubuntu:ubuntu "${WINEPREFIX}" \
|
||||
&& mkdir /virtualenvs \
|
||||
&& chown -R ubuntu:ubuntu /virtualenvs
|
||||
&& chown ubuntu:ubuntu "${WINEPREFIX}"
|
||||
|
||||
# Switch to non-root user
|
||||
USER ubuntu
|
||||
@@ -137,15 +117,27 @@ USER ubuntu
|
||||
# Initialize wine files to /home/ubuntu/.wine
|
||||
RUN wineboot --init
|
||||
|
||||
COPY wine /wine
|
||||
WORKDIR /backend
|
||||
|
||||
|
||||
FROM dependencies AS deployment
|
||||
FROM base AS uv-install
|
||||
|
||||
WORKDIR /backend
|
||||
|
||||
COPY --from=poetry /virtualenvs /virtualenvs
|
||||
COPY pyproject.toml poetry.lock /backend/
|
||||
RUN chown -R ubuntu:ubuntu /backend
|
||||
|
||||
COPY pyproject.toml uv.lock /backend/
|
||||
|
||||
USER ubuntu
|
||||
|
||||
# Install dependencies to /backend/.venv
|
||||
RUN uv sync --locked
|
||||
|
||||
|
||||
FROM developer AS deployment
|
||||
|
||||
COPY --from=uv-install /backend/.venv /backend/.venv
|
||||
COPY pyproject.toml uv.lock /backend/
|
||||
|
||||
COPY manage.py /backend
|
||||
COPY housekeeping.py /backend
|
||||
|
||||
@@ -229,7 +229,7 @@ class CompilerWrapper:
|
||||
# Shlex issue?
|
||||
logging.debug("Compilation failed: %s", e)
|
||||
raise CompilationError(str(e))
|
||||
except subprocess.TimeoutExpired as e:
|
||||
except subprocess.TimeoutExpired:
|
||||
raise CompilationError("Compilation failed: timeout expired")
|
||||
|
||||
if not object_path.exists():
|
||||
@@ -298,7 +298,7 @@ class CompilerWrapper:
|
||||
)
|
||||
except subprocess.CalledProcessError as e:
|
||||
raise AssemblyError.from_process_error(e)
|
||||
except subprocess.TimeoutExpired as e:
|
||||
except subprocess.TimeoutExpired:
|
||||
raise AssemblyError("Timeout expired")
|
||||
|
||||
# Assembly failed
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
from functools import wraps
|
||||
import logging
|
||||
|
||||
from typing import Callable, Any, Optional, TypeVar, ParamSpec
|
||||
from typing import Callable, Optional, TypeVar, ParamSpec
|
||||
from rest_framework.response import Response
|
||||
|
||||
logger = logging.getLogger(__file__)
|
||||
@@ -21,12 +21,10 @@ def globally_cacheable(
|
||||
def decorator(view_func: Callable[P, R]) -> Callable[P, R]:
|
||||
@wraps(view_func)
|
||||
def _wrapped_view(*args: P.args, **kwargs: P.kwargs) -> R:
|
||||
# First argument is typically request
|
||||
request: Any = args[0] if args else None
|
||||
response: R = view_func(*args, **kwargs)
|
||||
|
||||
# Build Cache-Control header
|
||||
directives = [f"public", f"max-age={max_age}"]
|
||||
directives = ["public", f"max-age={max_age}"]
|
||||
if stale_while_revalidate is not None:
|
||||
directives.append(f"stale-while-revalidate={stale_while_revalidate}")
|
||||
|
||||
|
||||
@@ -113,7 +113,7 @@ class DiffWrapper:
|
||||
},
|
||||
timeout=settings.OBJDUMP_TIMEOUT_SECONDS,
|
||||
)
|
||||
except subprocess.TimeoutExpired as e:
|
||||
except subprocess.TimeoutExpired:
|
||||
raise NmError("Timeout expired")
|
||||
except subprocess.CalledProcessError as e:
|
||||
raise NmError.from_process_error(e)
|
||||
@@ -198,7 +198,7 @@ class DiffWrapper:
|
||||
},
|
||||
timeout=settings.OBJDUMP_TIMEOUT_SECONDS,
|
||||
)
|
||||
except subprocess.TimeoutExpired as e:
|
||||
except subprocess.TimeoutExpired:
|
||||
raise ObjdumpError("Timeout expired")
|
||||
except subprocess.CalledProcessError as e:
|
||||
raise ObjdumpError.from_process_error(e)
|
||||
@@ -287,7 +287,7 @@ class DiffWrapper:
|
||||
mydump = DiffWrapper.get_dump(
|
||||
compiled_elf, platform, diff_label, config, objdump_flags
|
||||
)
|
||||
except Exception as e:
|
||||
except Exception:
|
||||
mydump = ""
|
||||
|
||||
try:
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import logging
|
||||
from typing import Callable, Optional, TYPE_CHECKING, Union
|
||||
from typing import Callable, TYPE_CHECKING, Union
|
||||
|
||||
from django.contrib import auth
|
||||
from django.contrib.auth.models import User
|
||||
@@ -13,7 +13,7 @@ from .models.profile import Profile
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from .models.github import GitHubUser
|
||||
pass
|
||||
|
||||
|
||||
class AnonymousUser(auth.models.AnonymousUser):
|
||||
|
||||
@@ -11,7 +11,7 @@ from ..models.scratch import gen_scratch_id
|
||||
class Migration(migrations.Migration):
|
||||
initial = True
|
||||
|
||||
dependencies: List[Tuple[str, str]] = []
|
||||
dependencies: List[Tuple[str, str]] = [] # type: ignore
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
|
||||
@@ -13,7 +13,7 @@ def populate_preset_fk(apps: Apps, schema_editor: BaseDatabaseSchemaEditor) -> N
|
||||
if scratch.preset is not None:
|
||||
try:
|
||||
preset = Preset.objects.get(name=scratch.preset)
|
||||
except:
|
||||
except Exception:
|
||||
continue
|
||||
scratch.preset_fk = preset
|
||||
scratch.save(update_fields=["preset_fk"])
|
||||
|
||||
@@ -3,7 +3,6 @@ from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("coreapp", "0058_rename_gcc272sn_to_gcc272sn0004"),
|
||||
]
|
||||
|
||||
@@ -75,7 +75,6 @@ def set_family_field(apps: Apps, schema_editor: BaseDatabaseSchemaEditor) -> Non
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("coreapp", "0059_scratch_family_alter_scratch_parent"),
|
||||
]
|
||||
|
||||
@@ -5,7 +5,6 @@ from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("coreapp", "0061_remove_githubuser_access_token"),
|
||||
]
|
||||
|
||||
@@ -78,7 +78,6 @@ class GitHubUser(models.Model):
|
||||
)
|
||||
|
||||
try:
|
||||
scope_str = str(response_json["scope"])
|
||||
access_token = str(response_json["access_token"])
|
||||
except KeyError:
|
||||
raise MalformedGitHubApiResponseException()
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import json
|
||||
import logging
|
||||
from typing import Any, List, Sequence
|
||||
from typing import Any, Sequence
|
||||
|
||||
from django.db import models
|
||||
from django.contrib import admin
|
||||
|
||||
@@ -1,20 +1,16 @@
|
||||
from typing import TYPE_CHECKING, Any, Dict, List, Optional
|
||||
|
||||
from django.contrib.auth.models import User
|
||||
from django.core.exceptions import ImproperlyConfigured
|
||||
from html_json_forms.serializers import JSONFormSerializer
|
||||
from rest_framework import serializers
|
||||
from rest_framework.exceptions import APIException
|
||||
from rest_framework.fields import SerializerMethodField
|
||||
from rest_framework.relations import HyperlinkedRelatedField, SlugRelatedField
|
||||
from rest_framework.reverse import reverse
|
||||
from rest_framework.relations import SlugRelatedField
|
||||
|
||||
from coreapp import platforms
|
||||
|
||||
from . import compilers
|
||||
from .flags import LanguageFlagSet
|
||||
from .libraries import Library
|
||||
from .middleware import Request
|
||||
from .models.github import GitHubUser
|
||||
from .models.preset import Preset
|
||||
from .models.profile import Profile
|
||||
@@ -123,14 +119,14 @@ class PresetSerializer(serializers.ModelSerializer[Preset]):
|
||||
def validate_platform(self, platform: str) -> str:
|
||||
try:
|
||||
platforms.from_id(platform)
|
||||
except:
|
||||
except Exception:
|
||||
raise serializers.ValidationError(f"Unknown platform: {platform}")
|
||||
return platform
|
||||
|
||||
def validate_compiler(self, compiler: str) -> str:
|
||||
try:
|
||||
compilers.from_id(compiler)
|
||||
except:
|
||||
except Exception:
|
||||
raise serializers.ValidationError(f"Unknown compiler: {compiler}")
|
||||
return compiler
|
||||
|
||||
@@ -167,14 +163,14 @@ class ScratchCreateSerializer(serializers.Serializer[None]):
|
||||
def validate_platform(self, platform: str) -> str:
|
||||
try:
|
||||
platforms.from_id(platform)
|
||||
except:
|
||||
except Exception:
|
||||
raise serializers.ValidationError(f"Unknown platform: {platform}")
|
||||
return platform
|
||||
|
||||
def validate_compiler(self, compiler: str) -> str:
|
||||
try:
|
||||
compilers.from_id(compiler)
|
||||
except:
|
||||
except Exception:
|
||||
raise serializers.ValidationError(f"Unknown compiler: {compiler}")
|
||||
return compiler
|
||||
|
||||
|
||||
@@ -17,7 +17,6 @@ def requiresCompiler(*compilers: Compiler) -> Callable[..., Any]:
|
||||
|
||||
|
||||
class BaseTestCase(APITestCase):
|
||||
|
||||
def setUp(self) -> None:
|
||||
super().setUp()
|
||||
self.client.credentials(HTTP_USER_AGENT="Firefrogz 1.0")
|
||||
|
||||
@@ -227,7 +227,15 @@ nop
|
||||
len(result.elf_object), 0, "The compilation result should be non-null"
|
||||
)
|
||||
|
||||
@parameterized.expand(input=[(c,) for c in compilers.available_compilers() if not isinstance(c, DummyCompiler)], name_func=all_compilers_name_func, skip_on_empty=True) # type: ignore
|
||||
@parameterized.expand(
|
||||
input=[
|
||||
(c,)
|
||||
for c in compilers.available_compilers()
|
||||
if not isinstance(c, DummyCompiler)
|
||||
],
|
||||
name_func=all_compilers_name_func,
|
||||
skip_on_empty=True,
|
||||
) # type: ignore
|
||||
def test_all_compilers(self, compiler: Compiler) -> None:
|
||||
"""
|
||||
Ensure that we can run a simple compilation/diff for all available compilers
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
from typing import Any, Dict
|
||||
|
||||
from django.test import Client
|
||||
|
||||
from coreapp.compilers import GCC281PM
|
||||
from coreapp.models.preset import Preset
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import tempfile
|
||||
from unittest.mock import Mock, patch
|
||||
|
||||
from coreapp.models.github import GitHubUser
|
||||
from coreapp.models.profile import Profile
|
||||
|
||||
@@ -407,7 +407,7 @@ class ScratchDetailTests(BaseTestCase):
|
||||
# fork the fork
|
||||
response = self.client.post(reverse("scratch-fork", args=[fork.slug]))
|
||||
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
|
||||
fork2: Scratch = Scratch.objects.get(slug=response.json()["slug"])
|
||||
Scratch.objects.get(slug=response.json()["slug"])
|
||||
|
||||
# verify the family holds all three
|
||||
response = self.client.get(reverse("scratch-family", args=[root.slug]))
|
||||
@@ -420,7 +420,6 @@ class ScratchDetailTests(BaseTestCase):
|
||||
# fork the root
|
||||
response = self.client.post(reverse("scratch-fork", args=[root.slug]))
|
||||
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
|
||||
fork = response.json()
|
||||
|
||||
# verify the family holds both, in creation order
|
||||
response = self.client.get(reverse("scratch-family", args=[root.slug]))
|
||||
@@ -477,7 +476,7 @@ class ScratchDetailTests(BaseTestCase):
|
||||
}
|
||||
|
||||
scratch1 = self.create_scratch(scratch1_dict)
|
||||
scratch2 = self.create_scratch(scratch2_dict)
|
||||
self.create_scratch(scratch2_dict)
|
||||
|
||||
response = self.client.get(reverse("scratch-family", args=[scratch1.slug]))
|
||||
self.assertEqual(len(response.json()), 1)
|
||||
|
||||
@@ -34,7 +34,6 @@ class SingleCompilerDetail(APIView):
|
||||
platform: Optional[str] = "",
|
||||
compiler: Optional[str] = "",
|
||||
) -> Response:
|
||||
|
||||
filtered = [
|
||||
c for c in compilers.available_compilers() if c.platform.id == platform
|
||||
]
|
||||
|
||||
@@ -21,12 +21,12 @@ class LibraryDetail(APIView):
|
||||
def libraries_json(platform: str = "") -> list[dict[str, object]]:
|
||||
return [
|
||||
{
|
||||
"name": l.name,
|
||||
"supported_versions": l.supported_versions,
|
||||
"platform": l.platform,
|
||||
"name": lib.name,
|
||||
"supported_versions": lib.supported_versions,
|
||||
"platform": lib.platform,
|
||||
}
|
||||
for l in libraries.available_libraries()
|
||||
if platform == "" or l.platform == platform
|
||||
for lib in libraries.available_libraries()
|
||||
if platform == "" or lib.platform == platform
|
||||
]
|
||||
|
||||
@condition(last_modified_func=lambda request: boot_time)
|
||||
|
||||
@@ -60,7 +60,6 @@ class PresetFilterSet(django_filters.FilterSet):
|
||||
globally_cacheable(max_age=300, stale_while_revalidate=30), name="dispatch"
|
||||
)
|
||||
class PresetViewSet(ModelViewSet): # type: ignore
|
||||
|
||||
permission_classes = [IsAdminUser | IsOwnerOrReadOnly]
|
||||
queryset = Preset.objects.all().annotate(num_scratches=Count("scratch__preset__id"))
|
||||
pagination_class = PresetPagination
|
||||
|
||||
@@ -194,8 +194,6 @@ def create_scratch(data: Dict[str, Any], allow_project: bool = False) -> Scratch
|
||||
|
||||
platform: Optional[Platform] = data.get("platform")
|
||||
compiler = compilers.from_id(data["compiler"])
|
||||
project = data.get("project")
|
||||
rom_address = data.get("rom_address")
|
||||
|
||||
if not platform:
|
||||
platform = compiler.platform
|
||||
|
||||
@@ -6,12 +6,11 @@ DB_PORT=${DATABASE_PORT:-5432}
|
||||
BE_HOST=${BACKEND_HOST:-0.0.0.0}
|
||||
BE_PORT=${BACKEND_PORT:-8000}
|
||||
|
||||
POETRY_VIRTUALENVS_PATH=/backend/virtualenvs
|
||||
|
||||
poetry install
|
||||
uv sync
|
||||
|
||||
poetry run /backend/compilers/download.py
|
||||
poetry run /backend/libraries/download.py
|
||||
uv run /backend/compilers/download.py
|
||||
uv run /backend/libraries/download.py
|
||||
|
||||
if command -v regedit &> /dev/null; then
|
||||
for reg in /backend/wine/*.reg; do
|
||||
@@ -27,6 +26,6 @@ until nc -z ${DB_HOST} ${DB_PORT} > /dev/null; do
|
||||
sleep 1
|
||||
done
|
||||
|
||||
poetry run /backend/manage.py migrate
|
||||
uv run /backend/manage.py migrate
|
||||
|
||||
poetry run /backend/manage.py runserver ${BE_HOST}:${BE_PORT}
|
||||
uv run /backend/manage.py runserver ${BE_HOST}:${BE_PORT}
|
||||
|
||||
@@ -14,12 +14,12 @@ until nc -z ${DB_HOST} ${DB_PORT} > /dev/null; do
|
||||
done
|
||||
|
||||
if [ -z "$CI" ]; then
|
||||
poetry run /backend/housekeeping.py
|
||||
uv run /backend/housekeeping.py
|
||||
else
|
||||
echo "Skipping housekeeping: running in CI environment"
|
||||
fi
|
||||
|
||||
poetry run /backend/manage.py migrate
|
||||
uv run /backend/manage.py migrate
|
||||
|
||||
if command -v regedit &> /dev/null; then
|
||||
for reg in /backend/wine/*.reg; do
|
||||
@@ -30,4 +30,4 @@ else
|
||||
echo "regedit command not found. Skipping registry import."
|
||||
fi
|
||||
|
||||
poetry run gunicorn -w ${WORKERS} decompme.wsgi --bind ${BE_HOST}:${BE_PORT}
|
||||
uv run gunicorn -w ${WORKERS} decompme.wsgi --bind ${BE_HOST}:${BE_PORT}
|
||||
|
||||
@@ -179,11 +179,11 @@ def main():
|
||||
if args.verbose:
|
||||
logger.setLevel("DEBUG")
|
||||
|
||||
if args.libraries_dir == None:
|
||||
if args.libraries_dir is None:
|
||||
args.libraries_dir = Path(os.path.dirname(os.path.realpath(__file__)))
|
||||
|
||||
libraries_yaml = (
|
||||
Path(os.path.dirname(os.path.realpath(__file__))) / f"libraries.yaml"
|
||||
Path(os.path.dirname(os.path.realpath(__file__))) / "libraries.yaml"
|
||||
)
|
||||
libraries_config = yaml.safe_load(libraries_yaml.open())
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#!/usr/bin/env python
|
||||
"""Django's command-line utility for administrative tasks."""
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
|
||||
1947
backend/poetry.lock
generated
1947
backend/poetry.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -1,50 +1,56 @@
|
||||
[tool.poetry]
|
||||
[project]
|
||||
name = "backend"
|
||||
version = "0.1.0"
|
||||
description = ""
|
||||
authors = ["Decomp.me team"]
|
||||
license = "MIT"
|
||||
package-mode = false
|
||||
authors = [
|
||||
{name = "Decomp.me team"}
|
||||
]
|
||||
license = {text = "MIT"}
|
||||
requires-python = ">=3.10"
|
||||
dependencies = [
|
||||
"django-cors-headers>=4.6.0",
|
||||
"django-environ>=0.11.2",
|
||||
"django-filter>=24.3",
|
||||
"djangorestframework>=3.15.2",
|
||||
"psycopg2-binary>=2.9.10",
|
||||
"jwt>=1.3.1",
|
||||
"PyGithub>=2.5.0",
|
||||
"drf-extensions>=0.7.1",
|
||||
"tzdata==2024.2",
|
||||
"Pillow==11.0",
|
||||
"html-json-forms>=1.1.1",
|
||||
"django-resized>=1.0.3",
|
||||
"django-cleanup>=9.0.0",
|
||||
"m2c @ git+https://github.com/matt-kempster/m2c.git",
|
||||
"asm-differ @ git+https://github.com/simonlindholm/asm-differ.git",
|
||||
"sentry-sdk>=2.19.0",
|
||||
"django-session-timeout>=0.1.0",
|
||||
"django>=5.1.3",
|
||||
"requests>=2.32.3",
|
||||
"setuptools>=75.6.0",
|
||||
"debugpy>=1.8.13",
|
||||
"gunicorn>=23.0.0",
|
||||
]
|
||||
|
||||
[tool.poetry.dependencies]
|
||||
python = "^3.10"
|
||||
django-cors-headers = "^4.6.0"
|
||||
django-environ = "^0.11.2"
|
||||
django-filter = "^24.3"
|
||||
djangorestframework = "^3.15.2"
|
||||
psycopg2-binary = "^2.9.10"
|
||||
jwt = "^1.3.1"
|
||||
PyGithub = "^2.5.0"
|
||||
drf-extensions = "^0.7.1"
|
||||
tzdata = "2024.2"
|
||||
Pillow = "11.0"
|
||||
html-json-forms = "^1.1.1"
|
||||
django-resized = "^1.0.3"
|
||||
django-cleanup = "^9.0.0"
|
||||
m2c = {git="https://github.com/matt-kempster/m2c.git"}
|
||||
asm-differ = {git="https://github.com/simonlindholm/asm-differ.git"}
|
||||
sentry-sdk = "^2.19.0"
|
||||
django-session-timeout = "^0.1.0"
|
||||
django = "^5.1.3"
|
||||
requests = "^2.32.3"
|
||||
setuptools = "^75.6.0"
|
||||
debugpy = "^1.8.13"
|
||||
gunicorn = "^23.0.0"
|
||||
|
||||
[tool.poetry.group.dev.dependencies]
|
||||
black = "^24.10.0"
|
||||
usort = "^1.0.8.post1"
|
||||
django-stubs-ext = "^5.1.1"
|
||||
django-stubs = "^5.1.1"
|
||||
djangorestframework-stubs = "^3.15.1"
|
||||
types-requests = "^2.32.0.20241016"
|
||||
parameterized = "^0.9.0"
|
||||
mypy = "^1.13.0"
|
||||
responses = "0.25.3"
|
||||
[dependency-groups]
|
||||
dev = [
|
||||
"ruff>=0.8.0",
|
||||
"usort>=1.0.8",
|
||||
"django-stubs-ext>=5.1.1",
|
||||
"django-stubs>=5.1.1",
|
||||
"djangorestframework-stubs>=3.15.1",
|
||||
"types-requests>=2.32.0.20241016",
|
||||
"parameterized>=0.9.0",
|
||||
"mypy>=1.13.0",
|
||||
"responses==0.25.3",
|
||||
]
|
||||
|
||||
[build-system]
|
||||
requires = ["poetry-core>=1.0.0"]
|
||||
build-backend = "poetry.core.masonry.api"
|
||||
requires = ["hatchling"]
|
||||
build-backend = "hatchling.build"
|
||||
|
||||
[tool.black]
|
||||
extend-exclude = '^/(local_files)/'
|
||||
[tool.hatch.metadata]
|
||||
allow-direct-references = true
|
||||
|
||||
[tool.hatch.build.targets.wheel]
|
||||
packages = ["coreapp", "decompme"]
|
||||
|
||||
1482
backend/uv.lock
generated
Normal file
1482
backend/uv.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -25,7 +25,7 @@ Dependencies:
|
||||
- Python >=3.10
|
||||
- Node.js >=14
|
||||
- [Yarn](https://yarnpkg.com/getting-started/install)
|
||||
- [Poetry](https://python-poetry.org/docs/#installing-with-the-official-installer)
|
||||
- [uv](https://docs.astral.sh/uv/getting-started/installation/)
|
||||
|
||||
---
|
||||
Create a file to hold environment variables:
|
||||
@@ -38,29 +38,30 @@ touch .env.local
|
||||
cd backend
|
||||
```
|
||||
|
||||
* Install Python dependencies with [poetry](https://python-poetry.org/docs/#installing-with-the-official-installer)
|
||||
* Install Python dependencies with [uv](https://docs.astral.sh/uv/getting-started/installation/)
|
||||
|
||||
```shell
|
||||
poetry install
|
||||
uv sync
|
||||
```
|
||||
|
||||
- Install compilers
|
||||
```shell
|
||||
poetry run python compilers/download.py
|
||||
uv run python compilers/download.py
|
||||
```
|
||||
|
||||
- Install libraries
|
||||
```shell
|
||||
poetry run python libraries/download.py
|
||||
uv run python libraries/download.py
|
||||
```
|
||||
|
||||
- Set up the database
|
||||
```shell
|
||||
poetry run python manage.py migrate
|
||||
uv run python manage.py migrate
|
||||
```
|
||||
|
||||
- Start the API server
|
||||
```shell
|
||||
poetry run python manage.py runserver
|
||||
uv run python manage.py runserver
|
||||
```
|
||||
|
||||
---
|
||||
@@ -98,8 +99,8 @@ yarn dev
|
||||
|
||||
If you modify any database models (`models.py`), you'll need to run the following to update the database:
|
||||
```shell
|
||||
poetry run python manage.py makemigrations
|
||||
poetry run python manage.py migrate
|
||||
uv run python manage.py makemigrations
|
||||
uv run python manage.py migrate
|
||||
```
|
||||
|
||||
### Running tests
|
||||
@@ -107,7 +108,7 @@ poetry run python manage.py migrate
|
||||
To ensure everything is working properly, you can run the unit tests in the backend folder.
|
||||
|
||||
```shell
|
||||
poetry run python manage.py test
|
||||
uv run python manage.py test
|
||||
```
|
||||
|
||||
### Frontend styling
|
||||
@@ -131,6 +132,7 @@ yarn lint --fix
|
||||
- Check backend
|
||||
```shell
|
||||
cd backend
|
||||
poetry run mypy
|
||||
poetry run black .
|
||||
uv run mypy
|
||||
uv run ruff check .
|
||||
uv run ruff format .
|
||||
```
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
After signing in with GitHub, you can make yourself an admin with the following:
|
||||
|
||||
```
|
||||
$ poetry run python3 manage.py shell
|
||||
$ uv run python3 manage.py shell
|
||||
>>> from django.contrib.auth.models import User
|
||||
>>> user = User.objects.get(username="your_username")
|
||||
>>> user.is_staff = True
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
### Configuring vscode for development
|
||||
|
||||
Poetry creates a virtualenv where packages for the site are installed. You can set your python interpreter path in vscode to use this virtualenv's interpreter, which will allow a much nicer backend development experience.
|
||||
uv creates a virtual environment where packages for the site are installed. You can set your python interpreter path in vscode to use this virtual environment's interpreter, which will allow a much nicer backend development experience.
|
||||
|
||||
1. Inside the `backend/` directory, run `poetry debug info` and copy the "Path:" property under the "Virtualenv" category.
|
||||
1. Inside the `backend/` directory, run `uv run which python` and copy the output path.
|
||||
|
||||
<img width="580" alt="image" src="https://user-images.githubusercontent.com/2985314/190146150-4ac8ecdd-dcfa-4e8e-a8b2-4913044aa088.png">
|
||||
|
||||
|
||||
Reference in New Issue
Block a user