Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ repos:

- repo: https://github.com/astral-sh/ruff-pre-commit
# Pinned Ruff version used by requirements.txt.
rev: v0.15.12
rev: v0.16.1
hooks:
- id: ruff
name: lint with ruff
Expand All @@ -71,7 +71,7 @@ repos:
name: format with ruff

- repo: https://github.com/DavidAnson/markdownlint-cli2
rev: v0.22.1
rev: v0.23.2
hooks:
- id: markdownlint-cli2
name: Lint markdown files
Expand Down
1 change: 1 addition & 0 deletions src/addonStoreApi/addonApiVersion.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
# For more details see COPYING.md

from typing import NamedTuple

from addonStoreApi.transformedSubmissions import StoreInfoProvider


Expand Down
8 changes: 4 additions & 4 deletions src/addonStoreApi/addonCollector.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,19 @@
# This file may be used under the terms of the AGPL3 (GNU Affero General Public License version 3).
# For more details see COPYING.md

from collections.abc import Generator, Iterable
from functools import lru_cache
import json
import re
from collections.abc import Generator, Iterable
from functools import lru_cache
from glob import glob

from tasks.dataFolder import DataFolder

from .supportedLanguage import SupportedLanguage
from .addonApiVersion import SupportedAddonApiVersion
from .supportedLanguage import SupportedLanguage
from .transformedSubmissions import (
StoreInfoProvider,
Channels,
StoreInfoProvider,
)


Expand Down
3 changes: 2 additions & 1 deletion src/addonStoreApi/transformedSubmissions.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,14 @@
"""Module to abstract the details for the layout for the transformed submissions"""

import enum
from tasks.dataFolder import DataFolder
import glob
import json
import logging
import os
from typing import TYPE_CHECKING

from tasks.dataFolder import DataFolder

if TYPE_CHECKING:
from addonStoreApi.addonApiVersion import MajorMinorPatch

Expand Down
51 changes: 24 additions & 27 deletions src/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,45 +2,42 @@
# This file may be used under the terms of the AGPL3 (GNU Affero General Public License version 3).
# For more details see COPYING.md

import typing
import hashlib
import hmac
import logging
import os
from http import HTTPStatus

from werkzeug.routing import BaseConverter, ValidationError
from addonStoreApi.addonApiVersion import MajorMinorPatch
from tasks.dataFolder import DataFolder
from tasks.health import check_health
from datetime import datetime
import re
import subprocess
import threading
from queue import Queue, Empty
from werkzeug.exceptions import NotFound
from datetime import datetime
from http import HTTPStatus
from queue import Empty, Queue

from flask import (
Flask,
Response,
request,
jsonify,
current_app,
jsonify,
request,
)
from flask_cors import CORS, cross_origin
from prometheus_flask_exporter import PrometheusMetrics
from prometheus_client import Counter
import re
from prometheus_flask_exporter import PrometheusMetrics
from werkzeug.exceptions import NotFound
from werkzeug.routing import BaseConverter, ValidationError

from addonStoreApi.addonApiVersion import SupportedAddonApiVersion
from addonStoreApi.supportedLanguage import SupportedLanguage
from addonStoreApi.addonApiVersion import MajorMinorPatch, SupportedAddonApiVersion
from addonStoreApi.addonCollector import (
FileCollector,
)
from addonStoreApi.supportedLanguage import SupportedLanguage
from addonStoreApi.transformedSubmissions import (
StoreInfoProvider,
Channels,
StoreInfoProvider,
)
import hmac
import hashlib
import subprocess
from frontend import frontend
from tasks.dataFolder import DataFolder
from tasks.health import check_health

""" app.py gets loaded automatically by Flask
Use this to configure routing.
Expand Down Expand Up @@ -86,7 +83,7 @@ def process_metrics_queue():
metric_func()

except Exception as e:
log.warning(f"Error processing metrics: {str(e)}")
log.warning(f"Error processing metrics: {e!s}")

def ensure_metrics_worker():
"""Ensure the metrics worker thread is running."""
Expand All @@ -104,7 +101,7 @@ def queue_metric(metric_func):
timeout=0.1,
) # Short timeout to prevent blocking
except Exception as e:
log.warning(f"Failed to queue metric: {str(e)}")
log.warning(f"Failed to queue metric: {e!s}")

# Initialize Prometheus metrics with path excluded from auth
metrics = PrometheusMetrics(app)
Expand Down Expand Up @@ -305,7 +302,7 @@ def throw():

@DataFolder.accessForReading
def _all(
includeChannels: typing.List[Channels],
includeChannels: list[Channels],
language: str,
apiVersion: MajorMinorPatch,
) -> Response:
Expand Down Expand Up @@ -344,7 +341,7 @@ def _all(

@DataFolder.accessForReading
def _latest(
includeChannels: typing.List[Channels],
includeChannels: list[Channels],
language: str,
) -> Response:
try:
Expand Down Expand Up @@ -447,7 +444,7 @@ def verify_github_signature(payload_body, signature_header):
# Compare signatures
return hmac.compare_digest(signature, expected_signature)
except Exception as e:
log.error(f"Error verifying webhook signature: {str(e)}")
log.error(f"Error verifying webhook signature: {e!s}")
return False

@app.route("/update", methods=["POST"])
Expand Down Expand Up @@ -587,9 +584,9 @@ def update_repo():
log.info(f"Repository updated successfully to {target_hash}")

except subprocess.CalledProcessError as e:
log.error(f"Git operation failed: {str(e)}")
log.error(f"Git operation failed: {e!s}")
except Exception as e:
log.error(f"Update failed: {str(e)}")
log.error(f"Update failed: {e!s}")
finally:
DataFolder._update_in_progress = False

Expand Down
26 changes: 12 additions & 14 deletions src/frontend/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,25 @@
# This file may be used under the terms of the AGPL3 (GNU Affero General Public License version 3).
# For more details see COPYING.md

from dataclasses import dataclass
import dataclasses
from enum import Enum
from functools import cached_property, lru_cache
import json
import logging
import os
from dataclasses import dataclass
from datetime import date
from enum import Enum
from functools import cached_property, lru_cache
from typing import Any, Literal

from babel import Locale
from babel.dates import format_date
from flask import Blueprint, render_template, request

from addonStoreApi.addonApiVersion import MajorMinorPatch, SupportedAddonApiVersion
from addonStoreApi.addonCollector import FileCollector
from addonStoreApi.supportedLanguage import SupportedLanguage

from addonStoreApi.addonApiVersion import MajorMinorPatch, SupportedAddonApiVersion
from addonStoreApi.transformedSubmissions import Channels, StoreInfoProvider
from tasks.dataFolder import DataFolder
from babel.dates import format_date
from babel import Locale
from datetime import date

# Don't use getenv or environ.get,
# as we want to fail if $COPYRIGHT_YEARS is not set
Expand Down Expand Up @@ -164,12 +164,10 @@ def matchingAddons(self) -> list[dict[str, Any]]:
else:
# No search term;
# just return all add-ons sorted by the specified field
return list(
sorted(
addonList,
key=self._getSortValue,
reverse=self.sortReverse,
),
return sorted(
addonList,
key=self._getSortValue,
reverse=self.sortReverse,
)

@cached_property
Expand Down
17 changes: 9 additions & 8 deletions src/tasks/dataFolder.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,19 @@
# This file may be used under the terms of the AGPL3 (GNU Affero General Public License version 3).
# For more details see COPYING.md

from enum import IntEnum
from functools import wraps
import logging
import os
import pathlib
import subprocess
import threading
from collections.abc import Callable
from contextlib import contextmanager
from enum import IntEnum
from functools import wraps
from time import time
from typing import Callable, Optional

from portalocker import AlreadyLocked, Lock
from portalocker.constants import LockFlags
import threading
from contextlib import contextmanager

"""
A set of tools which are used to ensure safe access to the addon store data folder.
Expand Down Expand Up @@ -156,7 +157,7 @@ def initialize():
DataFolder.log.warning("Found stale git index lock, cleaning up")
os.remove(os.path.join(repo_path, ".git", "index.lock"))
except Exception as e:
DataFolder.log.error(f"Error cleaning up git locks: {str(e)}")
DataFolder.log.error(f"Error cleaning up git locks: {e!s}")

# Configure git for safe directory access
DataFolder.log.info("Configuring git safe directory")
Expand Down Expand Up @@ -192,7 +193,7 @@ def _updateCacheHash():
f"Cache hash updated to: {DataFolder._current_hash}",
)
except subprocess.CalledProcessError as e:
DataFolder.log.error(f"Failed to update cache hash: {str(e)}")
DataFolder.log.error(f"Failed to update cache hash: {e!s}")
# If we fail to get the hash but had a previous hash, keep using it
if DataFolder._current_hash is None:
# If we've never had a hash, use a fallback
Expand Down Expand Up @@ -304,7 +305,7 @@ def readData(folder: str):
def wrapper(*args, **kwargs):
# If this thread is already performing a read,
# there is no need to create a new read file.
readFile: Optional[pathlib.Path] = None
readFile: pathlib.Path | None = None
if not _ReadTracker.threadIsInRead():
# Ensure the writer is aware a read is ongoing
# This call can be blocked by the writer
Expand Down
4 changes: 3 additions & 1 deletion src/tasks/health.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@

import logging
from http import HTTPStatus

from flask import jsonify

from .dataFolder import DataFolder

log = logging.getLogger("addonStore.health")
Expand Down Expand Up @@ -39,7 +41,7 @@ def check_health():

except Exception as e:
# Log the actual stack trace/error internally
log.exception(f"Healthcheck failed: {str(e)}")
log.exception(f"Healthcheck failed: {e!s}")

# Return a generic, opaque error to the client
return jsonify(
Expand Down