82 lines
3.2 KiB
Python
82 lines
3.2 KiB
Python
"""A GitHub releases page, the sheet's usual link."""
|
|
|
|
from archipelago_tester.pipeline.download.handlers.base import LinkHandler
|
|
from archipelago_tester.pipeline.download.release_downloader import (
|
|
ReleaseDownloader,
|
|
)
|
|
from archipelago_tester.pipeline.download.release_identity import (
|
|
ReleaseIdentity,
|
|
)
|
|
from archipelago_tester.pipeline.download.release_picker import ReleasePicker
|
|
from archipelago_tester.pipeline.download.walk_back import WalkBack
|
|
|
|
|
|
class GitHubRelease(LinkHandler):
|
|
"""Resolve which release the link means, then fetch its apworld."""
|
|
|
|
def __init__(self, shapes, previous=None):
|
|
super().__init__(shapes)
|
|
self.previous = previous
|
|
|
|
def parse(self, link):
|
|
return self.shapes.releases(link)
|
|
|
|
def resolve(self, parsed, context):
|
|
"""The release this link resolves to, or None.
|
|
|
|
A hand-pinned tag prefix wins, then a link naming one exact
|
|
tag, then the search term. Runs every pass: it is the one call
|
|
that can report a new release, which is the only thing able to
|
|
change a previously failed answer.
|
|
"""
|
|
owner, repository, term, tag = parsed
|
|
picker = ReleasePicker(context, owner, repository, term)
|
|
overrides = context.config.get("release_overrides") or {}
|
|
prefix = overrides.get(context.game.name)
|
|
if prefix:
|
|
return picker.by_tag_prefix(prefix)
|
|
if tag:
|
|
return picker.by_tag(tag)
|
|
return picker.pick()
|
|
|
|
def fetch(self, parsed, context, release):
|
|
"""This release's apworld, walking back if it ships none.
|
|
|
|
Only that one cause is walked back from. "Ships another game's
|
|
apworld" must not be, since an older release of a multi-world
|
|
repo is precisely the wrong answer there.
|
|
"""
|
|
owner, repository = parsed[0], parsed[1]
|
|
downloader = ReleaseDownloader(
|
|
context=context,
|
|
release=release,
|
|
# What this row's date already says, so a re-upload of
|
|
# unchanged bytes keeps it instead of moving it forward.
|
|
previous_published_at=(self.previous or {}).get("published_at"),
|
|
)
|
|
downloaded, reason, info = downloader.run()
|
|
if (downloaded is not None or context.identifier is None
|
|
or downloader.cause != ReleaseDownloader.NO_APWORLD):
|
|
return downloaded, reason, info
|
|
fallback, reason = WalkBack(
|
|
context=context,
|
|
owner=owner,
|
|
repository=repository,
|
|
release=release,
|
|
).run(reason)
|
|
return fallback if fallback is not None else (None, reason, info)
|
|
|
|
def download(self, parsed, context):
|
|
release = self.resolve(parsed, context)
|
|
if release is None:
|
|
return None, "no release matched the search term in the link", None
|
|
identity = ReleaseIdentity(release)
|
|
repeat = identity.repeated(self.previous)
|
|
if repeat is not None:
|
|
return None, repeat, identity.failure(
|
|
{"published_at": None}, repeat)
|
|
downloaded, reason, info = self.fetch(parsed, context, release)
|
|
if downloaded is None:
|
|
return None, reason, identity.failure(info, reason)
|
|
return downloaded, reason, info
|