Merge branch 'more_docstrings' into 'master'

[checkupdates] Add more docstrings

See merge request fdroid/fdroidserver!1400
This commit is contained in:
Jochen Sprickerhof 2023-10-23 08:54:38 +00:00
commit f4b10cf839
2 changed files with 179 additions and 24 deletions

View file

@ -30,6 +30,7 @@ extensions = [
'numpydoc', 'numpydoc',
'sphinx.ext.autodoc', 'sphinx.ext.autodoc',
'sphinx.ext.autosummary', 'sphinx.ext.autosummary',
"sphinx.ext.intersphinx",
] ]
# Add any paths that contain templates here, relative to this directory. # Add any paths that contain templates here, relative to this directory.
@ -71,5 +72,6 @@ html_sidebars = {
html_split_index = True html_split_index = True
#numpydoc_validation_checks = {"all"} #numpydoc_validation_checks = {"all"}
intersphinx_mapping = {
"python": ("https://docs.python.org/3/", None),
}

View file

@ -32,6 +32,7 @@ import logging
import copy import copy
import urllib.parse import urllib.parse
from pathlib import Path from pathlib import Path
from typing import Optional, Union
from . import _ from . import _
from . import common from . import common
@ -40,11 +41,32 @@ from . import net
from .exception import VCSException, NoSubmodulesException, FDroidException, MetaDataException from .exception import VCSException, NoSubmodulesException, FDroidException, MetaDataException
# Check for a new version by looking at a document retrieved via HTTP. def check_http(app: metadata.App) -> tuple[Union[str, None], Union[int, None]]:
# The app's Update Check Data field is used to provide the information """Check for a new version by looking at a document retrieved via HTTP.
# required.
def check_http(app):
The app's UpdateCheckData field is used to provide the information
required.
Parameters
----------
app
The App instance to check for updates for.
Returns
-------
version
The found versionName or None if the versionName should be ignored
according to UpdateCheckIgnore.
vercode
The found versionCode or None if the versionCode should be ignored
according to UpdateCheckIgnore.
Raises
------
:exc:`~fdroidserver.exception.FDroidException`
If UpdateCheckData is missing or is an invalid URL or if there is no
match for the provided versionName or versionCode regex.
"""
if not app.UpdateCheckData: if not app.UpdateCheckData:
raise FDroidException('Missing Update Check Data') raise FDroidException('Missing Update Check Data')
@ -85,12 +107,37 @@ def check_http(app):
return (version, vercode) return (version, vercode)
def check_tags(app, pattern): def check_tags(app: metadata.App, pattern: str) -> tuple[str, int, str]:
"""Check for a new version by looking at the tags in the source repo. """Check for a new version by looking at the tags in the source repo.
Whether this can be used reliably or not depends on Whether this can be used reliably or not depends on
the development procedures used by the project's developers. Use it with the development procedures used by the project's developers. Use it with
caution, because it's inappropriate for many projects. caution, because it's inappropriate for many projects.
Parameters
----------
app
The App instance to check for updates for.
pattern
The pattern a tag needs to match to be considered.
Returns
-------
versionName
The highest found versionName.
versionCode
The highest found versionCode.
ref
The Git reference, commit hash or tag name, of the highest found
versionName, versionCode.
Raises
------
:exc:`~fdroidserver.exception.MetaDataException`
If this function is not suitable for the RepoType of the app or
information is missing to perform this type of check.
:exc:`~fdroidserver.exception.FDroidException`
If no matching tags or no information whatsoever could be found.
""" """
if app.RepoType == 'srclib': if app.RepoType == 'srclib':
build_dir = Path('build/srclib') / app.Repo build_dir = Path('build/srclib') / app.Repo
@ -224,12 +271,31 @@ def check_tags(app, pattern):
raise FDroidException(_("Couldn't find any version information")) raise FDroidException(_("Couldn't find any version information"))
def check_repomanifest(app, branch=None): def check_repomanifest(app: metadata.App, branch: Optional[str] = None) -> tuple[str, int]:
"""Check for a new version by looking at the AndroidManifest.xml at the HEAD of the source repo. """Check for a new version by looking at the AndroidManifest.xml at the HEAD of the source repo.
Whether this can be used reliably or not depends on Whether this can be used reliably or not depends on
the development procedures used by the project's developers. Use it with the development procedures used by the project's developers. Use it with
caution, because it's inappropriate for many projects. caution, because it's inappropriate for many projects.
Parameters
----------
app
The App instance to check for updates for.
branch
The VCS branch where to search for versionCode, versionName.
Returns
-------
versionName
The highest found versionName.
versionCode
The highest found versionCode.
Raises
------
:exc:`~fdroidserver.exception.FDroidException`
If no package id or no version information could be found.
""" """
if app.RepoType == 'srclib': if app.RepoType == 'srclib':
build_dir = Path('build/srclib') / app.Repo build_dir = Path('build/srclib') / app.Repo
@ -327,8 +393,8 @@ def check_gplay(app):
return (version.strip(), None) return (version.strip(), None)
def try_init_submodules(app, last_build, vcs): def try_init_submodules(app: metadata.App, last_build: metadata.Build, vcs: common.vcs):
"""Try to init submodules if the last build entry used them. """Try to init submodules if the last build entry uses them.
They might have been removed from the app's repo in the meantime, They might have been removed from the app's repo in the meantime,
so if we can't find any submodules we continue with the updates check. so if we can't find any submodules we continue with the updates check.
@ -343,19 +409,44 @@ def try_init_submodules(app, last_build, vcs):
logging.info("submodule broken for {}".format(_getappname(app))) logging.info("submodule broken for {}".format(_getappname(app)))
# Return all directories under startdir that contain any of the manifest def dirs_with_manifest(startdir: str):
# files, and thus are probably an Android project. """Find directories containing a manifest file.
def dirs_with_manifest(startdir):
Yield all directories under startdir that contain any of the manifest
files, and thus are probably an Android project.
Parameters
----------
startdir
Directory to be walked down for search
Yields
------
path : :class:`pathlib.Path` or None
A directory that contains a manifest file of an Android project, None if
no directory could be found
"""
for root, _dirs, files in os.walk(startdir): for root, _dirs, files in os.walk(startdir):
if any(m in files for m in [ if any(m in files for m in [
'AndroidManifest.xml', 'pom.xml', 'build.gradle', 'build.gradle.kts']): 'AndroidManifest.xml', 'pom.xml', 'build.gradle', 'build.gradle.kts']):
yield Path(root) yield Path(root)
# Tries to find a new subdir starting from the root build_dir. Returns said def possible_subdirs(app: metadata.App):
# subdir relative to the build dir if found, None otherwise. """Try to find a new subdir starting from the root build_dir.
def possible_subdirs(app):
Yields said subdir relative to the build dir if found, None otherwise.
Parameters
----------
app
The app to check for subdirs
Yields
------
subdir : :class:`pathlib.Path` or None
A possible subdir, None if no subdir could be found
"""
if app.RepoType == 'srclib': if app.RepoType == 'srclib':
build_dir = Path('build/srclib') / app.Repo build_dir = Path('build/srclib') / app.Repo
else: else:
@ -372,15 +463,33 @@ def possible_subdirs(app):
yield subdir yield subdir
def _getappname(app): def _getappname(app: metadata.App) -> str:
return common.get_app_display_name(app) return common.get_app_display_name(app)
def _getcvname(app): def _getcvname(app: metadata.App) -> str:
return '%s (%s)' % (app.CurrentVersion, app.CurrentVersionCode) return '%s (%s)' % (app.CurrentVersion, app.CurrentVersionCode)
def fetch_autoname(app, tag): def fetch_autoname(app: metadata.App, tag: str) -> Optional[str]:
"""Fetch AutoName.
Get the to be displayed name of an app from the source code and adjust the
App instance in case it is different name has been found.
Parameters
----------
app
The App instance to get the AutoName for.
tag
Tag to fetch AutoName at.
Returns
-------
commitmsg
Commit message about the name change. None in case checking for the
name is disabled, a VCSException occured or no name could be found.
"""
if not app.RepoType or app.UpdateCheckMode in ('None', 'Static') \ if not app.RepoType or app.UpdateCheckMode in ('None', 'Static') \
or app.UpdateCheckName == "Ignore": or app.UpdateCheckName == "Ignore":
return None return None
@ -418,7 +527,26 @@ def fetch_autoname(app, tag):
return commitmsg return commitmsg
def operate_vercode(operation, vercode): def operate_vercode(operation: str, vercode: int) -> int:
"""Calculate a new versionCode from a mathematical operation.
Parameters
----------
operation
The operation to execute to get the new versionCode.
vercode
The versionCode for replacing "%c" in the operation.
Returns
-------
vercode
The new versionCode obtained by executing the operation.
Raises
------
:exc:`~fdroidserver.exception.MetaDataException`
If the operation is invalid.
"""
if not common.VERCODE_OPERATION_RE.match(operation): if not common.VERCODE_OPERATION_RE.match(operation):
raise MetaDataException(_('Invalid VercodeOperation: {field}') raise MetaDataException(_('Invalid VercodeOperation: {field}')
.format(field=operation)) .format(field=operation))
@ -429,9 +557,28 @@ def operate_vercode(operation, vercode):
return vercode return vercode
def checkupdates_app(app): def checkupdates_app(app: metadata.App) -> None:
"""Check for new versions and updated name of a single app.
Also write back changes to the metadata file and create a Git commit if
requested.
Parameters
----------
app
The app to check for updates for.
Raises
------
:exc:`~fdroidserver.exception.MetaDataException`
If the app has an invalid UpdateCheckMode or AutoUpdateMode.
:exc:`~fdroidserver.exception.FDroidException`
If no version information could be found, the current version is newer
than the found version, auto-update was requested but an app has no
CurrentVersionCode or (Git) commiting the changes failed.
"""
# If a change is made, commitmsg should be set to a description of it. # If a change is made, commitmsg should be set to a description of it.
# Only if this is set will changes be written back to the metadata. # Only if this is set, changes will be written back to the metadata.
commitmsg = None commitmsg = None
tag = None tag = None
@ -576,14 +723,15 @@ def checkupdates_app(app):
raise FDroidException("Git commit failed") raise FDroidException("Git commit failed")
def get_last_build_from_app(app): def get_last_build_from_app(app: metadata.App) -> metadata.Build:
"""Get the last build entry of an app."""
if app.get('Builds'): if app.get('Builds'):
return app['Builds'][-1] return app['Builds'][-1]
else: else:
return metadata.Build() return metadata.Build()
def status_update_json(processed, failed): def status_update_json(processed: list, failed: dict) -> None:
"""Output a JSON file with metadata about this run.""" """Output a JSON file with metadata about this run."""
logging.debug(_('Outputting JSON')) logging.debug(_('Outputting JSON'))
output = common.setup_status_output(start_timestamp) output = common.setup_status_output(start_timestamp)
@ -600,6 +748,11 @@ start_timestamp = time.gmtime()
def main(): def main():
"""Check for updates for one or more apps.
The behaviour of this function is influenced by the configuration file as
well as command line parameters.
"""
global config, options global config, options
# Parse command line... # Parse command line...