mirror of
https://github.com/arcan1s/ahriman.git
synced 2025-05-05 12:43:49 +00:00
Compare commits
4 Commits
aaededa303
...
7bd7f95f76
Author | SHA1 | Date | |
---|---|---|---|
7bd7f95f76 | |||
375374c396 | |||
d1ad5ecc11 | |||
1eb4d8e47f |
@ -82,6 +82,7 @@ limit-inference-results=100
|
|||||||
# List of plugins (as comma separated values of python module names) to load,
|
# List of plugins (as comma separated values of python module names) to load,
|
||||||
# usually to register additional checkers.
|
# usually to register additional checkers.
|
||||||
load-plugins=pylint.extensions.docparams,
|
load-plugins=pylint.extensions.docparams,
|
||||||
|
pylint.extensions.bad_builtin,
|
||||||
definition_order,
|
definition_order,
|
||||||
import_order,
|
import_order,
|
||||||
|
|
||||||
@ -131,6 +132,8 @@ attr-naming-style=snake_case
|
|||||||
# style.
|
# style.
|
||||||
#attr-rgx=
|
#attr-rgx=
|
||||||
|
|
||||||
|
bad-functions=print,
|
||||||
|
|
||||||
# Bad variable names which should always be refused, separated by a comma.
|
# Bad variable names which should always be refused, separated by a comma.
|
||||||
bad-names=foo,
|
bad-names=foo,
|
||||||
bar,
|
bar,
|
||||||
|
File diff suppressed because it is too large
Load Diff
Before Width: | Height: | Size: 1.1 MiB After Width: | Height: | Size: 1.2 MiB |
@ -228,6 +228,14 @@ ahriman.models.result module
|
|||||||
:no-undoc-members:
|
:no-undoc-members:
|
||||||
:show-inheritance:
|
:show-inheritance:
|
||||||
|
|
||||||
|
ahriman.models.scan\_paths module
|
||||||
|
---------------------------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.models.scan_paths
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
|
||||||
ahriman.models.sign\_settings module
|
ahriman.models.sign\_settings module
|
||||||
------------------------------------
|
------------------------------------
|
||||||
|
|
||||||
|
@ -81,7 +81,9 @@ Authorized users are stored inside internal database, if any of external provide
|
|||||||
|
|
||||||
Build related configuration. Group name can refer to architecture, e.g. ``build:x86_64`` can be used for x86_64 architecture specific settings.
|
Build related configuration. Group name can refer to architecture, e.g. ``build:x86_64`` can be used for x86_64 architecture specific settings.
|
||||||
|
|
||||||
|
* ``allowed_scan_paths`` - paths to be used for implicit dependencies scan, scape separated list of paths, optional.
|
||||||
* ``archbuild_flags`` - additional flags passed to ``archbuild`` command, space separated list of strings, optional.
|
* ``archbuild_flags`` - additional flags passed to ``archbuild`` command, space separated list of strings, optional.
|
||||||
|
* ``blacklisted_scan_paths`` - paths to be excluded for implicit dependencies scan, scape separated list of paths, optional. Normally all elements of this option must be child paths of any of ``allowed_scan_paths`` element.
|
||||||
* ``build_command`` - default build command, string, required.
|
* ``build_command`` - default build command, string, required.
|
||||||
* ``ignore_packages`` - list packages to ignore during a regular update (manual update will still work), space separated list of strings, optional.
|
* ``ignore_packages`` - list packages to ignore during a regular update (manual update will still work), space separated list of strings, optional.
|
||||||
* ``include_debug_packages`` - distribute debug packages, boolean, optional, default ``yes``.
|
* ``include_debug_packages`` - distribute debug packages, boolean, optional, default ``yes``.
|
||||||
@ -132,7 +134,7 @@ Web server settings. This feature requires ``aiohttp`` libraries to be installed
|
|||||||
* ``port`` - port to bind, integer, optional.
|
* ``port`` - port to bind, integer, optional.
|
||||||
* ``service_only`` - disable status routes (including logs), boolean, optional, default ``no``.
|
* ``service_only`` - disable status routes (including logs), boolean, optional, default ``no``.
|
||||||
* ``static_path`` - path to directory with static files, string, required.
|
* ``static_path`` - path to directory with static files, string, required.
|
||||||
* ``templates`` - path to templates directories, space separated list of strings, required.
|
* ``templates`` - path to templates directories, space separated list of paths, required.
|
||||||
* ``unix_socket`` - path to the listening unix socket, string, optional. If set, server will create the socket on the specified address which can (and will) be used by application. Note, that unlike usual host/port configuration, unix socket allows to perform requests without authorization.
|
* ``unix_socket`` - path to the listening unix socket, string, optional. If set, server will create the socket on the specified address which can (and will) be used by application. Note, that unlike usual host/port configuration, unix socket allows to perform requests without authorization.
|
||||||
* ``unix_socket_unsafe`` - set unsafe (o+w) permissions to unix socket, boolean, optional, default ``yes``. This option is enabled by default, because it is supposed that unix socket is created in safe environment (only web service is supposed to be used in unsafe), but it can be disabled by configuration.
|
* ``unix_socket_unsafe`` - set unsafe (o+w) permissions to unix socket, boolean, optional, default ``yes``. This option is enabled by default, because it is supposed that unix socket is created in safe environment (only web service is supposed to be used in unsafe), but it can be disabled by configuration.
|
||||||
* ``wait_timeout`` - wait timeout in seconds, maximum amount of time to be waited before lock will be free, integer, optional.
|
* ``wait_timeout`` - wait timeout in seconds, maximum amount of time to be waited before lock will be free, integer, optional.
|
||||||
@ -254,7 +256,7 @@ Section name must be either ``email`` (plus optional architecture name, e.g. ``e
|
|||||||
* ``ssl`` - SSL mode for SMTP connection, one of ``ssl``, ``starttls``, ``disabled``, optional, default ``disabled``.
|
* ``ssl`` - SSL mode for SMTP connection, one of ``ssl``, ``starttls``, ``disabled``, optional, default ``disabled``.
|
||||||
* ``template`` - Jinja2 template name, string, required.
|
* ``template`` - Jinja2 template name, string, required.
|
||||||
* ``template_full`` - Jinja2 template name for full package description index, string, optional.
|
* ``template_full`` - Jinja2 template name for full package description index, string, optional.
|
||||||
* ``templates`` - path to templates directories, space separated list of strings, required.
|
* ``templates`` - path to templates directories, space separated list of paths, required.
|
||||||
* ``user`` - SMTP user to authenticate, string, optional.
|
* ``user`` - SMTP user to authenticate, string, optional.
|
||||||
|
|
||||||
``html`` type
|
``html`` type
|
||||||
@ -267,7 +269,7 @@ Section name must be either ``html`` (plus optional architecture name, e.g. ``ht
|
|||||||
* ``link_path`` - prefix for HTML links, string, required.
|
* ``link_path`` - prefix for HTML links, string, required.
|
||||||
* ``path`` - path to html report file, string, required.
|
* ``path`` - path to html report file, string, required.
|
||||||
* ``template`` - Jinja2 template name, string, required.
|
* ``template`` - Jinja2 template name, string, required.
|
||||||
* ``templates`` - path to templates directories, space separated list of strings, required.
|
* ``templates`` - path to templates directories, space separated list of paths, required.
|
||||||
|
|
||||||
``remote-call`` type
|
``remote-call`` type
|
||||||
^^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^^^
|
||||||
@ -292,7 +294,7 @@ Section name must be either ``telegram`` (plus optional architecture name, e.g.
|
|||||||
* ``link_path`` - prefix for HTML links, string, required.
|
* ``link_path`` - prefix for HTML links, string, required.
|
||||||
* ``template`` - Jinja2 template name, string, required.
|
* ``template`` - Jinja2 template name, string, required.
|
||||||
* ``template_type`` - ``parse_mode`` to be passed to telegram API, one of ``MarkdownV2``, ``HTML``, ``Markdown``, string, optional, default ``HTML``.
|
* ``template_type`` - ``parse_mode`` to be passed to telegram API, one of ``MarkdownV2``, ``HTML``, ``Markdown``, string, optional, default ``HTML``.
|
||||||
* ``templates`` - path to templates directories, space separated list of strings, required.
|
* ``templates`` - path to templates directories, space separated list of paths, required.
|
||||||
* ``timeout`` - HTTP request timeout in seconds, integer, optional, default is ``30``.
|
* ``timeout`` - HTTP request timeout in seconds, integer, optional, default is ``30``.
|
||||||
|
|
||||||
``upload`` group
|
``upload`` group
|
||||||
|
@ -370,7 +370,16 @@ TL;DR
|
|||||||
|
|
||||||
You can even rebuild the whole repository (which is particular useful in case if you would like to change packager) if you do not supply ``--depends-on`` option. This action will automatically increment ``pkgrel`` value; in case if you don't want to, the ``--no-increment`` option has to be supplied.
|
You can even rebuild the whole repository (which is particular useful in case if you would like to change packager) if you do not supply ``--depends-on`` option. This action will automatically increment ``pkgrel`` value; in case if you don't want to, the ``--no-increment`` option has to be supplied.
|
||||||
|
|
||||||
However, note that you do not need to rebuild repository in case if you just changed signing option, just use ``repo-sign`` command instead.
|
However, note that you do not need to rebuild repository in case if you just changed signing option, just use ``repo-sign`` command instead.
|
||||||
|
|
||||||
|
Automated broken dependencies detection
|
||||||
|
"""""""""""""""""""""""""""""""""""""""
|
||||||
|
|
||||||
|
After the success build the application extracts all linked libraries and used directories and stores them in database. During the check process, the application extracts pacman databases and checks if file names have been changed (e.g. new python release caused ``/usr/lib/python3.x`` directory renaming to ``/usr/lib/python3.y`` or soname for a linked library has been changed). In case if broken dependencies have been detected, the package will be added to the rebuild queue.
|
||||||
|
|
||||||
|
In order to disable this check completely, the ``--no-check-files`` flag can be used.
|
||||||
|
|
||||||
|
In addition, there is possibility to control paths which will be used for checking, by using options ``build.allowed_scan_paths`` and ``build.blacklisted_scan_paths``. Leaving ``build.allowed_scan_paths`` blank will effectively disable any check too.
|
||||||
|
|
||||||
How to install built packages
|
How to install built packages
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
# Maintainer: Evgeniy Alekseev
|
# Maintainer: Evgeniy Alekseev
|
||||||
|
|
||||||
pkgname='ahriman'
|
pkgname='ahriman'
|
||||||
pkgver=2.13.8
|
pkgver=2.14.0
|
||||||
pkgrel=1
|
pkgrel=1
|
||||||
pkgdesc="ArcH linux ReposItory MANager"
|
pkgdesc="ArcH linux ReposItory MANager"
|
||||||
arch=('any')
|
arch=('any')
|
||||||
|
@ -50,8 +50,12 @@ allow_read_only = yes
|
|||||||
;salt =
|
;salt =
|
||||||
|
|
||||||
[build]
|
[build]
|
||||||
|
; List of paths to be used for implicit dependency scan
|
||||||
|
allowed_scan_paths = /usr/lib
|
||||||
; List of additional flags passed to archbuild command.
|
; List of additional flags passed to archbuild command.
|
||||||
;archbuild_flags =
|
;archbuild_flags =
|
||||||
|
; List of paths to be excluded for implicit dependency scan. Usually they should be subpaths of allowed_scan_paths
|
||||||
|
blacklisted_scan_paths = /usr/lib/cmake
|
||||||
; Path to build command
|
; Path to build command
|
||||||
;build_command =
|
;build_command =
|
||||||
; List of packages to be ignored during automatic updates.
|
; List of packages to be ignored during automatic updates.
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
.TH AHRIMAN "1" "2024\-05\-12" "ahriman" "Generated Python Manual"
|
.TH AHRIMAN "1" "2024\-08\-23" "ahriman" "Generated Python Manual"
|
||||||
.SH NAME
|
.SH NAME
|
||||||
ahriman
|
ahriman
|
||||||
.SH SYNOPSIS
|
.SH SYNOPSIS
|
||||||
@ -391,7 +391,7 @@ PKGBUILD variable or function name. If variable is a function, it must end with
|
|||||||
path to file which contains function or variable value. If not set, the value will be read from stdin
|
path to file which contains function or variable value. If not set, the value will be read from stdin
|
||||||
|
|
||||||
.SH COMMAND \fI\,'ahriman patch\-list'\/\fR
|
.SH COMMAND \fI\,'ahriman patch\-list'\/\fR
|
||||||
usage: ahriman patch\-list [\-h] [\-e] [\-v VARIABLE] [package]
|
usage: ahriman patch\-list [\-h] [\-e] [\-v VARIABLE] package
|
||||||
|
|
||||||
list available patches for the package
|
list available patches for the package
|
||||||
|
|
||||||
|
@ -86,7 +86,7 @@ _shtab_ahriman_options=(
|
|||||||
{-a,--architecture}"[filter by target architecture (default\: None)]:architecture:"
|
{-a,--architecture}"[filter by target architecture (default\: None)]:architecture:"
|
||||||
{-c,--configuration}"[configuration path (default\: \/etc\/ahriman.ini)]:configuration:"
|
{-c,--configuration}"[configuration path (default\: \/etc\/ahriman.ini)]:configuration:"
|
||||||
"--force[force run, remove file lock (default\: False)]"
|
"--force[force run, remove file lock (default\: False)]"
|
||||||
{-l,--lock}"[lock file (default\: \/tmp\/ahriman.lock)]:lock:"
|
{-l,--lock}"[lock file (default\: ahriman.pid)]:lock:"
|
||||||
"--log-handler[explicit log handler specification. If none set, the handler will be guessed from environment (default\: None)]:log_handler:(console syslog journald)"
|
"--log-handler[explicit log handler specification. If none set, the handler will be guessed from environment (default\: None)]:log_handler:(console syslog journald)"
|
||||||
{-q,--quiet}"[force disable any logging (default\: False)]"
|
{-q,--quiet}"[force disable any logging (default\: False)]"
|
||||||
{--report,--no-report}"[force enable or disable reporting to web service (default\: True)]:report:"
|
{--report,--no-report}"[force enable or disable reporting to web service (default\: True)]:report:"
|
||||||
@ -280,7 +280,7 @@ _shtab_ahriman_patch_list_options=(
|
|||||||
"(- : *)"{-h,--help}"[show this help message and exit]"
|
"(- : *)"{-h,--help}"[show this help message and exit]"
|
||||||
{-e,--exit-code}"[return non-zero exit status if result is empty (default\: False)]"
|
{-e,--exit-code}"[return non-zero exit status if result is empty (default\: False)]"
|
||||||
"*"{-v,--variable}"[if set, show only patches for specified PKGBUILD variables (default\: None)]:variable:"
|
"*"{-v,--variable}"[if set, show only patches for specified PKGBUILD variables (default\: None)]:variable:"
|
||||||
":package base (default\: None):"
|
":package base:"
|
||||||
)
|
)
|
||||||
|
|
||||||
_shtab_ahriman_patch_remove_options=(
|
_shtab_ahriman_patch_remove_options=(
|
||||||
|
@ -17,4 +17,4 @@
|
|||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
#
|
#
|
||||||
__version__ = "2.13.8"
|
__version__ = "2.14.0"
|
||||||
|
@ -98,6 +98,7 @@ class Patch(Handler):
|
|||||||
PkgbuildPatch: created patch for the PKGBUILD function
|
PkgbuildPatch: created patch for the PKGBUILD function
|
||||||
"""
|
"""
|
||||||
if patch_path is None:
|
if patch_path is None:
|
||||||
|
# pylint: disable=bad-builtin
|
||||||
print("Post new function or variable value below. Press Ctrl-D to finish:", file=sys.stderr)
|
print("Post new function or variable value below. Press Ctrl-D to finish:", file=sys.stderr)
|
||||||
patch = "".join(list(sys.stdin))
|
patch = "".join(list(sys.stdin))
|
||||||
else:
|
else:
|
||||||
|
@ -77,5 +77,5 @@ class Update(Handler):
|
|||||||
Callable[[str], None]: in case if dry_run is set it will return print, logger otherwise
|
Callable[[str], None]: in case if dry_run is set it will return print, logger otherwise
|
||||||
"""
|
"""
|
||||||
def inner(line: str) -> None:
|
def inner(line: str) -> None:
|
||||||
return print(line) if dry_run else application.logger.info(line)
|
return print(line) if dry_run else application.logger.info(line) # pylint: disable=bad-builtin
|
||||||
return inner
|
return inner
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
#
|
#
|
||||||
import shutil
|
import shutil
|
||||||
|
|
||||||
|
from collections.abc import Generator
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
from ahriman.core.exceptions import CalledProcessError
|
from ahriman.core.exceptions import CalledProcessError
|
||||||
@ -38,10 +39,14 @@ class Sources(LazyLogging):
|
|||||||
DEFAULT_BRANCH(str): (class attribute) default branch to process git repositories.
|
DEFAULT_BRANCH(str): (class attribute) default branch to process git repositories.
|
||||||
Must be used only for local stored repositories, use RemoteSource descriptor instead for real packages
|
Must be used only for local stored repositories, use RemoteSource descriptor instead for real packages
|
||||||
DEFAULT_COMMIT_AUTHOR(tuple[str, str]): (class attribute) default commit author to be used if none set
|
DEFAULT_COMMIT_AUTHOR(tuple[str, str]): (class attribute) default commit author to be used if none set
|
||||||
|
GITCONFIG(dict[str, str]): (class attribute) git config options to suppress annoying hints
|
||||||
"""
|
"""
|
||||||
|
|
||||||
DEFAULT_BRANCH = "master" # default fallback branch
|
DEFAULT_BRANCH = "master" # default fallback branch
|
||||||
DEFAULT_COMMIT_AUTHOR = ("ahriman", "ahriman@localhost")
|
DEFAULT_COMMIT_AUTHOR = ("ahriman", "ahriman@localhost")
|
||||||
|
GITCONFIG = {
|
||||||
|
"init.defaultBranch": DEFAULT_BRANCH,
|
||||||
|
}
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def changes(source_dir: Path, last_commit_sha: str | None) -> str | None:
|
def changes(source_dir: Path, last_commit_sha: str | None) -> str | None:
|
||||||
@ -106,15 +111,15 @@ class Sources(LazyLogging):
|
|||||||
instance.fetch_until(sources_dir, branch=branch)
|
instance.fetch_until(sources_dir, branch=branch)
|
||||||
elif remote.git_url is not None:
|
elif remote.git_url is not None:
|
||||||
instance.logger.info("clone remote %s to %s using branch %s", remote.git_url, sources_dir, branch)
|
instance.logger.info("clone remote %s to %s using branch %s", remote.git_url, sources_dir, branch)
|
||||||
check_output("git", "clone", "--quiet", "--depth", "1", "--branch", branch, "--single-branch",
|
check_output(*instance.git(), "clone", "--quiet", "--depth", "1", "--branch", branch, "--single-branch",
|
||||||
remote.git_url, str(sources_dir), cwd=sources_dir.parent, logger=instance.logger)
|
remote.git_url, str(sources_dir), cwd=sources_dir.parent, logger=instance.logger)
|
||||||
else:
|
else:
|
||||||
# it will cause an exception later
|
# it will cause an exception later
|
||||||
instance.logger.error("%s is not initialized, but no remote provided", sources_dir)
|
instance.logger.error("%s is not initialized, but no remote provided", sources_dir)
|
||||||
|
|
||||||
# and now force reset to our branch
|
# and now force reset to our branch
|
||||||
check_output("git", "checkout", "--force", branch, cwd=sources_dir, logger=instance.logger)
|
check_output(*instance.git(), "checkout", "--force", branch, cwd=sources_dir, logger=instance.logger)
|
||||||
check_output("git", "reset", "--quiet", "--hard", f"origin/{branch}",
|
check_output(*instance.git(), "reset", "--quiet", "--hard", f"origin/{branch}",
|
||||||
cwd=sources_dir, logger=instance.logger)
|
cwd=sources_dir, logger=instance.logger)
|
||||||
|
|
||||||
# move content if required
|
# move content if required
|
||||||
@ -136,7 +141,7 @@ class Sources(LazyLogging):
|
|||||||
bool: True in case if there is any remote and false otherwise
|
bool: True in case if there is any remote and false otherwise
|
||||||
"""
|
"""
|
||||||
instance = Sources()
|
instance = Sources()
|
||||||
remotes = check_output("git", "remote", cwd=sources_dir, logger=instance.logger)
|
remotes = check_output(*instance.git(), "remote", cwd=sources_dir, logger=instance.logger)
|
||||||
return bool(remotes)
|
return bool(remotes)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
@ -150,7 +155,7 @@ class Sources(LazyLogging):
|
|||||||
instance = Sources()
|
instance = Sources()
|
||||||
if not (sources_dir / ".git").is_dir():
|
if not (sources_dir / ".git").is_dir():
|
||||||
# skip initializing in case if it was already
|
# skip initializing in case if it was already
|
||||||
check_output("git", "init", "--quiet", "--initial-branch", instance.DEFAULT_BRANCH,
|
check_output(*instance.git(), "init", "--quiet", "--initial-branch", instance.DEFAULT_BRANCH,
|
||||||
cwd=sources_dir, logger=instance.logger)
|
cwd=sources_dir, logger=instance.logger)
|
||||||
|
|
||||||
# extract local files...
|
# extract local files...
|
||||||
@ -220,7 +225,7 @@ class Sources(LazyLogging):
|
|||||||
return # no changes to push, just skip action
|
return # no changes to push, just skip action
|
||||||
|
|
||||||
git_url, branch = remote.git_source()
|
git_url, branch = remote.git_source()
|
||||||
check_output("git", "push", "--quiet", git_url, branch, cwd=sources_dir, logger=instance.logger)
|
check_output(*instance.git(), "push", "--quiet", git_url, branch, cwd=sources_dir, logger=instance.logger)
|
||||||
|
|
||||||
def add(self, sources_dir: Path, *pattern: str, intent_to_add: bool = False) -> None:
|
def add(self, sources_dir: Path, *pattern: str, intent_to_add: bool = False) -> None:
|
||||||
"""
|
"""
|
||||||
@ -241,7 +246,7 @@ class Sources(LazyLogging):
|
|||||||
self.logger.info("found matching files %s", found_files)
|
self.logger.info("found matching files %s", found_files)
|
||||||
# add them to index
|
# add them to index
|
||||||
args = ["--intent-to-add"] if intent_to_add else []
|
args = ["--intent-to-add"] if intent_to_add else []
|
||||||
check_output("git", "add", *args, *[str(fn.relative_to(sources_dir)) for fn in found_files],
|
check_output(*self.git(), "add", *args, *[str(fn.relative_to(sources_dir)) for fn in found_files],
|
||||||
cwd=sources_dir, logger=self.logger)
|
cwd=sources_dir, logger=self.logger)
|
||||||
|
|
||||||
def commit(self, sources_dir: Path, message: str | None = None,
|
def commit(self, sources_dir: Path, message: str | None = None,
|
||||||
@ -264,15 +269,16 @@ class Sources(LazyLogging):
|
|||||||
if message is None:
|
if message is None:
|
||||||
message = f"Autogenerated commit at {utcnow()}"
|
message = f"Autogenerated commit at {utcnow()}"
|
||||||
args = ["--message", message]
|
args = ["--message", message]
|
||||||
environment: dict[str, str] = {}
|
|
||||||
|
|
||||||
if commit_author is None:
|
if commit_author is None:
|
||||||
commit_author = self.DEFAULT_COMMIT_AUTHOR
|
commit_author = self.DEFAULT_COMMIT_AUTHOR
|
||||||
user, email = commit_author
|
user, email = commit_author
|
||||||
environment["GIT_AUTHOR_NAME"] = environment["GIT_COMMITTER_NAME"] = user
|
gitconfig = {
|
||||||
environment["GIT_AUTHOR_EMAIL"] = environment["GIT_COMMITTER_EMAIL"] = email
|
"user.email": email,
|
||||||
|
"user.name": user,
|
||||||
|
}
|
||||||
|
|
||||||
check_output("git", "commit", "--quiet", *args, cwd=sources_dir, logger=self.logger, environment=environment)
|
check_output(*self.git(gitconfig), "commit", "--quiet", *args, cwd=sources_dir, logger=self.logger)
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
@ -290,7 +296,7 @@ class Sources(LazyLogging):
|
|||||||
args = []
|
args = []
|
||||||
if sha is not None:
|
if sha is not None:
|
||||||
args.append(sha)
|
args.append(sha)
|
||||||
return check_output("git", "diff", *args, cwd=sources_dir, logger=self.logger)
|
return check_output(*self.git(), "diff", *args, cwd=sources_dir, logger=self.logger)
|
||||||
|
|
||||||
def fetch_until(self, sources_dir: Path, *, branch: str | None = None, commit_sha: str | None = None) -> None:
|
def fetch_until(self, sources_dir: Path, *, branch: str | None = None, commit_sha: str | None = None) -> None:
|
||||||
"""
|
"""
|
||||||
@ -306,18 +312,37 @@ class Sources(LazyLogging):
|
|||||||
|
|
||||||
commits_count = 1
|
commits_count = 1
|
||||||
while commit_sha is not None:
|
while commit_sha is not None:
|
||||||
command = ["git", "fetch", "--quiet", "--depth", str(commits_count)]
|
command = self.git() + ["fetch", "--quiet", "--depth", str(commits_count)]
|
||||||
if branch is not None:
|
if branch is not None:
|
||||||
command += ["origin", branch]
|
command += ["origin", branch]
|
||||||
check_output(*command, cwd=sources_dir, logger=self.logger) # fetch one more level
|
check_output(*command, cwd=sources_dir, logger=self.logger) # fetch one more level
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# check if there is an object in current git directory
|
# check if there is an object in current git directory
|
||||||
check_output("git", "cat-file", "-e", commit_sha, cwd=sources_dir, logger=self.logger)
|
check_output(*self.git(), "cat-file", "-e", commit_sha, cwd=sources_dir, logger=self.logger)
|
||||||
commit_sha = None # reset search
|
commit_sha = None # reset search
|
||||||
except CalledProcessError:
|
except CalledProcessError:
|
||||||
commits_count += 1 # increase depth
|
commits_count += 1 # increase depth
|
||||||
|
|
||||||
|
def git(self, gitconfig: dict[str, str] | None = None) -> list[str]:
|
||||||
|
"""
|
||||||
|
git command prefix
|
||||||
|
|
||||||
|
Args:
|
||||||
|
gitconfig(dict[str, str] | None, optional): additional git config flags if any (Default value = None)
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
list[str]: git command prefix with valid default flags
|
||||||
|
"""
|
||||||
|
gitconfig = gitconfig or {}
|
||||||
|
|
||||||
|
def configuration_flags() -> Generator[str, None, None]:
|
||||||
|
for option, value in (self.GITCONFIG | gitconfig).items():
|
||||||
|
yield "-c"
|
||||||
|
yield f"{option}=\"{value}\""
|
||||||
|
|
||||||
|
return ["git"] + list(configuration_flags())
|
||||||
|
|
||||||
def has_changes(self, sources_dir: Path) -> bool:
|
def has_changes(self, sources_dir: Path) -> bool:
|
||||||
"""
|
"""
|
||||||
check if there are changes in current git tree
|
check if there are changes in current git tree
|
||||||
@ -329,7 +354,7 @@ class Sources(LazyLogging):
|
|||||||
bool: True if there are uncommitted changes and False otherwise
|
bool: True if there are uncommitted changes and False otherwise
|
||||||
"""
|
"""
|
||||||
# there is --exit-code argument to diff, however, there might be other process errors
|
# there is --exit-code argument to diff, however, there might be other process errors
|
||||||
changes = check_output("git", "diff", "--cached", "--name-only", cwd=sources_dir, logger=self.logger)
|
changes = check_output(*self.git(), "diff", "--cached", "--name-only", cwd=sources_dir, logger=self.logger)
|
||||||
return bool(changes)
|
return bool(changes)
|
||||||
|
|
||||||
def head(self, sources_dir: Path, ref_name: str = "HEAD") -> str:
|
def head(self, sources_dir: Path, ref_name: str = "HEAD") -> str:
|
||||||
@ -344,7 +369,7 @@ class Sources(LazyLogging):
|
|||||||
str: HEAD commit hash
|
str: HEAD commit hash
|
||||||
"""
|
"""
|
||||||
# we might want to parse git files instead though
|
# we might want to parse git files instead though
|
||||||
return check_output("git", "rev-parse", ref_name, cwd=sources_dir, logger=self.logger)
|
return check_output(*self.git(), "rev-parse", ref_name, cwd=sources_dir, logger=self.logger)
|
||||||
|
|
||||||
def move(self, pkgbuild_dir: Path, sources_dir: Path) -> None:
|
def move(self, pkgbuild_dir: Path, sources_dir: Path) -> None:
|
||||||
"""
|
"""
|
||||||
@ -372,7 +397,7 @@ class Sources(LazyLogging):
|
|||||||
# create patch
|
# create patch
|
||||||
self.logger.info("apply patch %s from database at %s", patch.key, sources_dir)
|
self.logger.info("apply patch %s from database at %s", patch.key, sources_dir)
|
||||||
if patch.is_plain_diff:
|
if patch.is_plain_diff:
|
||||||
check_output("git", "apply", "--ignore-space-change", "--ignore-whitespace",
|
check_output(*self.git(), "apply", "--ignore-space-change", "--ignore-whitespace",
|
||||||
cwd=sources_dir, input_data=patch.serialize(), logger=self.logger)
|
cwd=sources_dir, input_data=patch.serialize(), logger=self.logger)
|
||||||
else:
|
else:
|
||||||
patch.write(sources_dir / "PKGBUILD")
|
patch.write(sources_dir / "PKGBUILD")
|
||||||
|
@ -169,6 +169,14 @@ CONFIGURATION_SCHEMA: ConfigurationSchema = {
|
|||||||
"build": {
|
"build": {
|
||||||
"type": "dict",
|
"type": "dict",
|
||||||
"schema": {
|
"schema": {
|
||||||
|
"allowed_scan_paths": {
|
||||||
|
"type": "list",
|
||||||
|
"coerce": "list",
|
||||||
|
"schema": {
|
||||||
|
"type": "path",
|
||||||
|
"coerce": "absolute_path",
|
||||||
|
},
|
||||||
|
},
|
||||||
"archbuild_flags": {
|
"archbuild_flags": {
|
||||||
"type": "list",
|
"type": "list",
|
||||||
"coerce": "list",
|
"coerce": "list",
|
||||||
@ -177,6 +185,14 @@ CONFIGURATION_SCHEMA: ConfigurationSchema = {
|
|||||||
"empty": False,
|
"empty": False,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
"blacklisted_scan_paths": {
|
||||||
|
"type": "list",
|
||||||
|
"coerce": "list",
|
||||||
|
"schema": {
|
||||||
|
"type": "path",
|
||||||
|
"coerce": "absolute_path",
|
||||||
|
},
|
||||||
|
},
|
||||||
"build_command": {
|
"build_command": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"required": True,
|
"required": True,
|
||||||
|
@ -80,7 +80,8 @@ class Executor(PackageInfo, Cleaner):
|
|||||||
# clear changes and update commit hash
|
# clear changes and update commit hash
|
||||||
self.reporter.package_changes_update(single.base, Changes(last_commit_sha))
|
self.reporter.package_changes_update(single.base, Changes(last_commit_sha))
|
||||||
# update dependencies list
|
# update dependencies list
|
||||||
dependencies = PackageArchive(self.paths.build_directory, single, self.pacman).depends_on()
|
package_archive = PackageArchive(self.paths.build_directory, single, self.pacman, self.scan_paths)
|
||||||
|
dependencies = package_archive.depends_on()
|
||||||
self.reporter.package_dependencies_update(single.base, dependencies)
|
self.reporter.package_dependencies_update(single.base, dependencies)
|
||||||
# update result set
|
# update result set
|
||||||
result.add_updated(single)
|
result.add_updated(single)
|
||||||
|
@ -29,6 +29,7 @@ from ahriman.models.packagers import Packagers
|
|||||||
from ahriman.models.pacman_synchronization import PacmanSynchronization
|
from ahriman.models.pacman_synchronization import PacmanSynchronization
|
||||||
from ahriman.models.repository_id import RepositoryId
|
from ahriman.models.repository_id import RepositoryId
|
||||||
from ahriman.models.repository_paths import RepositoryPaths
|
from ahriman.models.repository_paths import RepositoryPaths
|
||||||
|
from ahriman.models.scan_paths import ScanPaths
|
||||||
from ahriman.models.user import User
|
from ahriman.models.user import User
|
||||||
from ahriman.models.user_access import UserAccess
|
from ahriman.models.user_access import UserAccess
|
||||||
|
|
||||||
@ -46,6 +47,7 @@ class RepositoryProperties(LazyLogging):
|
|||||||
repo(Repo): repo commands wrapper instance
|
repo(Repo): repo commands wrapper instance
|
||||||
reporter(Client): build status reporter instance
|
reporter(Client): build status reporter instance
|
||||||
repository_id(RepositoryId): repository unique identifier
|
repository_id(RepositoryId): repository unique identifier
|
||||||
|
scan_paths(ScanPaths): scan paths for the implicit dependencies
|
||||||
sign(GPG): GPG wrapper instance
|
sign(GPG): GPG wrapper instance
|
||||||
triggers(TriggerLoader): triggers holder
|
triggers(TriggerLoader): triggers holder
|
||||||
vcs_allowed_age(int): maximal age of the VCS packages before they will be checked
|
vcs_allowed_age(int): maximal age of the VCS packages before they will be checked
|
||||||
@ -78,6 +80,11 @@ class RepositoryProperties(LazyLogging):
|
|||||||
self.reporter = Client.load(repository_id, configuration, database, report=report)
|
self.reporter = Client.load(repository_id, configuration, database, report=report)
|
||||||
self.triggers = TriggerLoader.load(repository_id, configuration)
|
self.triggers = TriggerLoader.load(repository_id, configuration)
|
||||||
|
|
||||||
|
self.scan_paths = ScanPaths(
|
||||||
|
allowed_paths=configuration.getpathlist("build", "allowed_scan_paths", fallback=[]),
|
||||||
|
blacklisted_paths=configuration.getpathlist("build", "blacklisted_scan_paths", fallback=[]),
|
||||||
|
)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def architecture(self) -> str:
|
def architecture(self) -> str:
|
||||||
"""
|
"""
|
||||||
|
@ -30,6 +30,7 @@ from ahriman.core.utils import walk
|
|||||||
from ahriman.models.dependencies import Dependencies
|
from ahriman.models.dependencies import Dependencies
|
||||||
from ahriman.models.filesystem_package import FilesystemPackage
|
from ahriman.models.filesystem_package import FilesystemPackage
|
||||||
from ahriman.models.package import Package
|
from ahriman.models.package import Package
|
||||||
|
from ahriman.models.scan_paths import ScanPaths
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
@ -39,13 +40,15 @@ class PackageArchive:
|
|||||||
|
|
||||||
Attributes:
|
Attributes:
|
||||||
package(Package): package descriptor
|
package(Package): package descriptor
|
||||||
root(Path): path to root filesystem
|
|
||||||
pacman(Pacman): alpm wrapper instance
|
pacman(Pacman): alpm wrapper instance
|
||||||
|
root(Path): path to root filesystem
|
||||||
|
scan_paths(ScanPaths): scan paths holder
|
||||||
"""
|
"""
|
||||||
|
|
||||||
root: Path
|
root: Path
|
||||||
package: Package
|
package: Package
|
||||||
pacman: Pacman
|
pacman: Pacman
|
||||||
|
scan_paths: ScanPaths
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def dynamic_needed(binary_path: Path) -> list[str]:
|
def dynamic_needed(binary_path: Path) -> list[str]:
|
||||||
@ -165,6 +168,10 @@ class PackageArchive:
|
|||||||
if any(package.package_name in base_packages for package in packages):
|
if any(package.package_name in base_packages for package in packages):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
# check path against the black/white listed
|
||||||
|
if not self.scan_paths.is_allowed(path):
|
||||||
|
continue
|
||||||
|
|
||||||
# remove explicit dependencies
|
# remove explicit dependencies
|
||||||
packages = [package for package in packages if package.is_root_package(packages, include_optional=False)]
|
packages = [package for package in packages if package.is_root_package(packages, include_optional=False)]
|
||||||
# remove optional dependencies
|
# remove optional dependencies
|
||||||
|
58
src/ahriman/models/scan_paths.py
Normal file
58
src/ahriman/models/scan_paths.py
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
#
|
||||||
|
# Copyright (c) 2021-2024 ahriman team.
|
||||||
|
#
|
||||||
|
# This file is part of ahriman
|
||||||
|
# (see https://github.com/arcan1s/ahriman).
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
#
|
||||||
|
from dataclasses import dataclass
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass(frozen=True, kw_only=True)
|
||||||
|
class ScanPaths:
|
||||||
|
"""
|
||||||
|
paths used for scan filesystem
|
||||||
|
|
||||||
|
Attributes:
|
||||||
|
allowed_paths(list[Path]): list of whitelisted paths
|
||||||
|
blacklisted_paths(list[Path]): list of paths to be skipped from scan
|
||||||
|
"""
|
||||||
|
|
||||||
|
allowed_paths: list[Path]
|
||||||
|
blacklisted_paths: list[Path]
|
||||||
|
|
||||||
|
def __post_init__(self) -> None:
|
||||||
|
"""
|
||||||
|
compute relative to / paths
|
||||||
|
"""
|
||||||
|
object.__setattr__(self, "allowed_paths", [path.relative_to("/") for path in self.allowed_paths])
|
||||||
|
object.__setattr__(self, "blacklisted_paths", [path.relative_to("/") for path in self.blacklisted_paths])
|
||||||
|
|
||||||
|
def is_allowed(self, path: Path) -> bool:
|
||||||
|
"""
|
||||||
|
check whether path is allowed to scan or not
|
||||||
|
|
||||||
|
Args:
|
||||||
|
path(Path): path to be checked
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
bool: ``True`` in case if :attr:`allowed_paths` contains element which is parent for the path and
|
||||||
|
:attr:`blacklisted_paths` doesn't and ``False`` otherwise
|
||||||
|
"""
|
||||||
|
if any(path.is_relative_to(blacklisted) for blacklisted in self.blacklisted_paths):
|
||||||
|
return False # path is blacklisted
|
||||||
|
# check if we actually have to check this path
|
||||||
|
return any(path.is_relative_to(allowed) for allowed in self.allowed_paths)
|
@ -67,7 +67,7 @@ class WaiterTaskFinished(WaiterResult):
|
|||||||
indicates whether the waiter completed with success or not
|
indicates whether the waiter completed with success or not
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Literal[True]: always False
|
Literal[True]: always ``True``
|
||||||
"""
|
"""
|
||||||
return True
|
return True
|
||||||
|
|
||||||
@ -82,7 +82,7 @@ class WaiterTimedOut(WaiterResult):
|
|||||||
indicates whether the waiter completed with success or not
|
indicates whether the waiter completed with success or not
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Literal[False]: always False
|
Literal[False]: always ``False``
|
||||||
"""
|
"""
|
||||||
return False
|
return False
|
||||||
|
|
||||||
@ -108,7 +108,7 @@ class Waiter:
|
|||||||
check if timer is out
|
check if timer is out
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
bool: True in case current monotonic time is more than :attr:`start_time` and :attr:`wait_timeout`
|
bool: ``True`` in case current monotonic time is more than :attr:`start_time` and :attr:`wait_timeout`
|
||||||
doesn't equal to 0
|
doesn't equal to 0
|
||||||
"""
|
"""
|
||||||
since_start = time.monotonic() - self.start_time
|
since_start = time.monotonic() - self.start_time
|
||||||
@ -124,7 +124,7 @@ class Waiter:
|
|||||||
**kwargs(Params.kwargs): keyword arguments for check call
|
**kwargs(Params.kwargs): keyword arguments for check call
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
WaiterResult: consumed time in seconds
|
WaiterResult: waiter result object
|
||||||
"""
|
"""
|
||||||
while not (timed_out := self.is_timed_out()) and in_progress(*args, **kwargs):
|
while not (timed_out := self.is_timed_out()) and in_progress(*args, **kwargs):
|
||||||
time.sleep(self.interval)
|
time.sleep(self.interval)
|
||||||
|
@ -74,7 +74,7 @@ def test_fetch_empty(remote_source: RemoteSource, mocker: MockerFixture) -> None
|
|||||||
check_output_mock.assert_not_called()
|
check_output_mock.assert_not_called()
|
||||||
|
|
||||||
|
|
||||||
def test_fetch_existing(remote_source: RemoteSource, mocker: MockerFixture) -> None:
|
def test_fetch_existing(sources: Sources, remote_source: RemoteSource, mocker: MockerFixture) -> None:
|
||||||
"""
|
"""
|
||||||
must fetch new package via fetch command
|
must fetch new package via fetch command
|
||||||
"""
|
"""
|
||||||
@ -86,18 +86,19 @@ def test_fetch_existing(remote_source: RemoteSource, mocker: MockerFixture) -> N
|
|||||||
head_mock = mocker.patch("ahriman.core.build_tools.sources.Sources.head", return_value="sha")
|
head_mock = mocker.patch("ahriman.core.build_tools.sources.Sources.head", return_value="sha")
|
||||||
|
|
||||||
local = Path("local")
|
local = Path("local")
|
||||||
assert Sources.fetch(local, remote_source) == "sha"
|
assert sources.fetch(local, remote_source) == "sha"
|
||||||
fetch_mock.assert_called_once_with(local, branch=remote_source.branch)
|
fetch_mock.assert_called_once_with(local, branch=remote_source.branch)
|
||||||
check_output_mock.assert_has_calls([
|
check_output_mock.assert_has_calls([
|
||||||
MockCall("git", "checkout", "--force", remote_source.branch, cwd=local, logger=pytest.helpers.anyvar(int)),
|
MockCall(*sources.git(), "checkout", "--force", remote_source.branch,
|
||||||
MockCall("git", "reset", "--quiet", "--hard", f"origin/{remote_source.branch}",
|
cwd=local, logger=pytest.helpers.anyvar(int)),
|
||||||
|
MockCall(*sources.git(), "reset", "--quiet", "--hard", f"origin/{remote_source.branch}",
|
||||||
cwd=local, logger=pytest.helpers.anyvar(int)),
|
cwd=local, logger=pytest.helpers.anyvar(int)),
|
||||||
])
|
])
|
||||||
move_mock.assert_called_once_with(local.resolve(), local)
|
move_mock.assert_called_once_with(local.resolve(), local)
|
||||||
head_mock.assert_called_once_with(local)
|
head_mock.assert_called_once_with(local)
|
||||||
|
|
||||||
|
|
||||||
def test_fetch_new(remote_source: RemoteSource, mocker: MockerFixture) -> None:
|
def test_fetch_new(sources: Sources, remote_source: RemoteSource, mocker: MockerFixture) -> None:
|
||||||
"""
|
"""
|
||||||
must fetch new package via clone command
|
must fetch new package via clone command
|
||||||
"""
|
"""
|
||||||
@ -107,19 +108,21 @@ def test_fetch_new(remote_source: RemoteSource, mocker: MockerFixture) -> None:
|
|||||||
head_mock = mocker.patch("ahriman.core.build_tools.sources.Sources.head", return_value="sha")
|
head_mock = mocker.patch("ahriman.core.build_tools.sources.Sources.head", return_value="sha")
|
||||||
|
|
||||||
local = Path("local")
|
local = Path("local")
|
||||||
assert Sources.fetch(local, remote_source) == "sha"
|
assert sources.fetch(local, remote_source) == "sha"
|
||||||
check_output_mock.assert_has_calls([
|
check_output_mock.assert_has_calls([
|
||||||
MockCall("git", "clone", "--quiet", "--depth", "1", "--branch", remote_source.branch, "--single-branch",
|
MockCall(*sources.git(), "clone", "--quiet", "--depth", "1", "--branch", remote_source.branch,
|
||||||
remote_source.git_url, str(local), cwd=local.parent, logger=pytest.helpers.anyvar(int)),
|
"--single-branch", remote_source.git_url, str(local),
|
||||||
MockCall("git", "checkout", "--force", remote_source.branch, cwd=local, logger=pytest.helpers.anyvar(int)),
|
cwd=local.parent, logger=pytest.helpers.anyvar(int)),
|
||||||
MockCall("git", "reset", "--quiet", "--hard", f"origin/{remote_source.branch}",
|
MockCall(*sources.git(), "checkout", "--force", remote_source.branch,
|
||||||
|
cwd=local, logger=pytest.helpers.anyvar(int)),
|
||||||
|
MockCall(*sources.git(), "reset", "--quiet", "--hard", f"origin/{remote_source.branch}",
|
||||||
cwd=local, logger=pytest.helpers.anyvar(int))
|
cwd=local, logger=pytest.helpers.anyvar(int))
|
||||||
])
|
])
|
||||||
move_mock.assert_called_once_with(local.resolve(), local)
|
move_mock.assert_called_once_with(local.resolve(), local)
|
||||||
head_mock.assert_called_once_with(local)
|
head_mock.assert_called_once_with(local)
|
||||||
|
|
||||||
|
|
||||||
def test_fetch_new_without_remote(mocker: MockerFixture) -> None:
|
def test_fetch_new_without_remote(sources: Sources, mocker: MockerFixture) -> None:
|
||||||
"""
|
"""
|
||||||
must fetch nothing in case if no remote set
|
must fetch nothing in case if no remote set
|
||||||
"""
|
"""
|
||||||
@ -129,10 +132,11 @@ def test_fetch_new_without_remote(mocker: MockerFixture) -> None:
|
|||||||
head_mock = mocker.patch("ahriman.core.build_tools.sources.Sources.head", return_value="sha")
|
head_mock = mocker.patch("ahriman.core.build_tools.sources.Sources.head", return_value="sha")
|
||||||
|
|
||||||
local = Path("local")
|
local = Path("local")
|
||||||
assert Sources.fetch(local, RemoteSource(source=PackageSource.Archive)) == "sha"
|
assert sources.fetch(local, RemoteSource(source=PackageSource.Archive)) == "sha"
|
||||||
check_output_mock.assert_has_calls([
|
check_output_mock.assert_has_calls([
|
||||||
MockCall("git", "checkout", "--force", Sources.DEFAULT_BRANCH, cwd=local, logger=pytest.helpers.anyvar(int)),
|
MockCall(*sources.git(), "checkout", "--force", sources.DEFAULT_BRANCH,
|
||||||
MockCall("git", "reset", "--quiet", "--hard", f"origin/{Sources.DEFAULT_BRANCH}",
|
cwd=local, logger=pytest.helpers.anyvar(int)),
|
||||||
|
MockCall(*sources.git(), "reset", "--quiet", "--hard", f"origin/{sources.DEFAULT_BRANCH}",
|
||||||
cwd=local, logger=pytest.helpers.anyvar(int))
|
cwd=local, logger=pytest.helpers.anyvar(int))
|
||||||
])
|
])
|
||||||
move_mock.assert_called_once_with(local.resolve(), local)
|
move_mock.assert_called_once_with(local.resolve(), local)
|
||||||
@ -153,15 +157,15 @@ def test_fetch_relative(remote_source: RemoteSource, mocker: MockerFixture) -> N
|
|||||||
head_mock.assert_called_once_with(local)
|
head_mock.assert_called_once_with(local)
|
||||||
|
|
||||||
|
|
||||||
def test_has_remotes(mocker: MockerFixture) -> None:
|
def test_has_remotes(sources: Sources, mocker: MockerFixture) -> None:
|
||||||
"""
|
"""
|
||||||
must ask for remotes
|
must ask for remotes
|
||||||
"""
|
"""
|
||||||
check_output_mock = mocker.patch("ahriman.core.build_tools.sources.check_output", return_value="origin")
|
check_output_mock = mocker.patch("ahriman.core.build_tools.sources.check_output", return_value="origin")
|
||||||
|
|
||||||
local = Path("local")
|
local = Path("local")
|
||||||
assert Sources.has_remotes(local)
|
assert sources.has_remotes(local)
|
||||||
check_output_mock.assert_called_once_with("git", "remote", cwd=local, logger=pytest.helpers.anyvar(int))
|
check_output_mock.assert_called_once_with(*sources.git(), "remote", cwd=local, logger=pytest.helpers.anyvar(int))
|
||||||
|
|
||||||
|
|
||||||
def test_has_remotes_empty(mocker: MockerFixture) -> None:
|
def test_has_remotes_empty(mocker: MockerFixture) -> None:
|
||||||
@ -172,7 +176,7 @@ def test_has_remotes_empty(mocker: MockerFixture) -> None:
|
|||||||
assert not Sources.has_remotes(Path("local"))
|
assert not Sources.has_remotes(Path("local"))
|
||||||
|
|
||||||
|
|
||||||
def test_init(mocker: MockerFixture) -> None:
|
def test_init(sources: Sources, mocker: MockerFixture) -> None:
|
||||||
"""
|
"""
|
||||||
must create empty repository at the specified path
|
must create empty repository at the specified path
|
||||||
"""
|
"""
|
||||||
@ -183,9 +187,9 @@ def test_init(mocker: MockerFixture) -> None:
|
|||||||
commit_mock = mocker.patch("ahriman.core.build_tools.sources.Sources.commit")
|
commit_mock = mocker.patch("ahriman.core.build_tools.sources.Sources.commit")
|
||||||
|
|
||||||
local = Path("local")
|
local = Path("local")
|
||||||
Sources.init(local)
|
sources.init(local)
|
||||||
check_output_mock.assert_called_once_with("git", "init", "--quiet", "--initial-branch", Sources.DEFAULT_BRANCH,
|
check_output_mock.assert_called_once_with(*sources.git(), "init", "--quiet", "--initial-branch",
|
||||||
cwd=local, logger=pytest.helpers.anyvar(int))
|
sources.DEFAULT_BRANCH, cwd=local, logger=pytest.helpers.anyvar(int))
|
||||||
add_mock.assert_called_once_with(local, "PKGBUILD", ".SRCINFO", "local")
|
add_mock.assert_called_once_with(local, "PKGBUILD", ".SRCINFO", "local")
|
||||||
commit_mock.assert_called_once_with(local)
|
commit_mock.assert_called_once_with(local)
|
||||||
|
|
||||||
@ -267,7 +271,7 @@ def test_patch_create_with_newline(mocker: MockerFixture) -> None:
|
|||||||
assert Sources.patch_create(Path("local"), "glob").endswith("\n")
|
assert Sources.patch_create(Path("local"), "glob").endswith("\n")
|
||||||
|
|
||||||
|
|
||||||
def test_push(package_ahriman: Package, mocker: MockerFixture) -> None:
|
def test_push(package_ahriman: Package, sources: Sources, mocker: MockerFixture) -> None:
|
||||||
"""
|
"""
|
||||||
must correctly push files to remote repository
|
must correctly push files to remote repository
|
||||||
"""
|
"""
|
||||||
@ -277,11 +281,11 @@ def test_push(package_ahriman: Package, mocker: MockerFixture) -> None:
|
|||||||
|
|
||||||
commit_author = ("commit author", "user@host")
|
commit_author = ("commit author", "user@host")
|
||||||
local = Path("local")
|
local = Path("local")
|
||||||
Sources.push(local, package_ahriman.remote, "glob", commit_author=commit_author)
|
sources.push(local, package_ahriman.remote, "glob", commit_author=commit_author)
|
||||||
add_mock.assert_called_once_with(local, "glob")
|
add_mock.assert_called_once_with(local, "glob")
|
||||||
commit_mock.assert_called_once_with(local, commit_author=commit_author)
|
commit_mock.assert_called_once_with(local, commit_author=commit_author)
|
||||||
check_output_mock.assert_called_once_with(
|
check_output_mock.assert_called_once_with(
|
||||||
"git", "push", "--quiet", package_ahriman.remote.git_url, package_ahriman.remote.branch,
|
*sources.git(), "push", "--quiet", package_ahriman.remote.git_url, package_ahriman.remote.branch,
|
||||||
cwd=local, logger=pytest.helpers.anyvar(int))
|
cwd=local, logger=pytest.helpers.anyvar(int))
|
||||||
|
|
||||||
|
|
||||||
@ -308,7 +312,7 @@ def test_add(sources: Sources, mocker: MockerFixture) -> None:
|
|||||||
sources.add(local, "pattern1", "pattern2")
|
sources.add(local, "pattern1", "pattern2")
|
||||||
glob_mock.assert_has_calls([MockCall("pattern1"), MockCall("pattern2")])
|
glob_mock.assert_has_calls([MockCall("pattern1"), MockCall("pattern2")])
|
||||||
check_output_mock.assert_called_once_with(
|
check_output_mock.assert_called_once_with(
|
||||||
"git", "add", "1", "2", "1", "2", cwd=local, logger=sources.logger
|
*sources.git(), "add", "1", "2", "1", "2", cwd=local, logger=sources.logger
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -323,7 +327,7 @@ def test_add_intent_to_add(sources: Sources, mocker: MockerFixture) -> None:
|
|||||||
sources.add(local, "pattern1", "pattern2", intent_to_add=True)
|
sources.add(local, "pattern1", "pattern2", intent_to_add=True)
|
||||||
glob_mock.assert_has_calls([MockCall("pattern1"), MockCall("pattern2")])
|
glob_mock.assert_has_calls([MockCall("pattern1"), MockCall("pattern2")])
|
||||||
check_output_mock.assert_called_once_with(
|
check_output_mock.assert_called_once_with(
|
||||||
"git", "add", "--intent-to-add", "1", "2", "1", "2", cwd=local, logger=sources.logger
|
*sources.git(), "add", "--intent-to-add", "1", "2", "1", "2", cwd=local, logger=sources.logger
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -350,13 +354,8 @@ def test_commit(sources: Sources, mocker: MockerFixture) -> None:
|
|||||||
user, email = sources.DEFAULT_COMMIT_AUTHOR
|
user, email = sources.DEFAULT_COMMIT_AUTHOR
|
||||||
assert sources.commit(local, message=message)
|
assert sources.commit(local, message=message)
|
||||||
check_output_mock.assert_called_once_with(
|
check_output_mock.assert_called_once_with(
|
||||||
"git", "commit", "--quiet", "--message", message,
|
*sources.git(), "-c", f"user.email=\"{email}\"", "-c", f"user.name=\"{user}\"",
|
||||||
cwd=local, logger=sources.logger, environment={
|
"commit", "--quiet", "--message", message, cwd=local, logger=sources.logger
|
||||||
"GIT_AUTHOR_NAME": user,
|
|
||||||
"GIT_AUTHOR_EMAIL": email,
|
|
||||||
"GIT_COMMITTER_NAME": user,
|
|
||||||
"GIT_COMMITTER_EMAIL": email,
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -383,13 +382,8 @@ def test_commit_author(sources: Sources, mocker: MockerFixture) -> None:
|
|||||||
user, email = author = ("commit author", "user@host")
|
user, email = author = ("commit author", "user@host")
|
||||||
assert sources.commit(Path("local"), message=message, commit_author=author)
|
assert sources.commit(Path("local"), message=message, commit_author=author)
|
||||||
check_output_mock.assert_called_once_with(
|
check_output_mock.assert_called_once_with(
|
||||||
"git", "commit", "--quiet", "--message", message,
|
*sources.git(), "-c", f"user.email=\"{email}\"", "-c", f"user.name=\"{user}\"",
|
||||||
cwd=local, logger=sources.logger, environment={
|
"commit", "--quiet", "--message", message, cwd=local, logger=sources.logger
|
||||||
"GIT_AUTHOR_NAME": user,
|
|
||||||
"GIT_AUTHOR_EMAIL": email,
|
|
||||||
"GIT_COMMITTER_NAME": user,
|
|
||||||
"GIT_COMMITTER_EMAIL": email,
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -404,13 +398,8 @@ def test_commit_autogenerated_message(sources: Sources, mocker: MockerFixture) -
|
|||||||
assert sources.commit(Path("local"))
|
assert sources.commit(Path("local"))
|
||||||
user, email = sources.DEFAULT_COMMIT_AUTHOR
|
user, email = sources.DEFAULT_COMMIT_AUTHOR
|
||||||
check_output_mock.assert_called_once_with(
|
check_output_mock.assert_called_once_with(
|
||||||
"git", "commit", "--quiet", "--message", pytest.helpers.anyvar(str, strict=True),
|
*sources.git(), "-c", f"user.email=\"{email}\"", "-c", f"user.name=\"{user}\"",
|
||||||
cwd=local, logger=sources.logger, environment={
|
"commit", "--quiet", "--message", pytest.helpers.anyvar(str, strict=True), cwd=local, logger=sources.logger
|
||||||
"GIT_AUTHOR_NAME": user,
|
|
||||||
"GIT_AUTHOR_EMAIL": email,
|
|
||||||
"GIT_COMMITTER_NAME": user,
|
|
||||||
"GIT_COMMITTER_EMAIL": email,
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -422,7 +411,7 @@ def test_diff(sources: Sources, mocker: MockerFixture) -> None:
|
|||||||
|
|
||||||
local = Path("local")
|
local = Path("local")
|
||||||
assert sources.diff(local)
|
assert sources.diff(local)
|
||||||
check_output_mock.assert_called_once_with("git", "diff", cwd=local, logger=sources.logger)
|
check_output_mock.assert_called_once_with(*sources.git(), "diff", cwd=local, logger=sources.logger)
|
||||||
|
|
||||||
|
|
||||||
def test_diff_specific(sources: Sources, mocker: MockerFixture) -> None:
|
def test_diff_specific(sources: Sources, mocker: MockerFixture) -> None:
|
||||||
@ -433,7 +422,7 @@ def test_diff_specific(sources: Sources, mocker: MockerFixture) -> None:
|
|||||||
|
|
||||||
local = Path("local")
|
local = Path("local")
|
||||||
assert sources.diff(local, "hash")
|
assert sources.diff(local, "hash")
|
||||||
check_output_mock.assert_called_once_with("git", "diff", "hash", cwd=local, logger=sources.logger)
|
check_output_mock.assert_called_once_with(*sources.git(), "diff", "hash", cwd=local, logger=sources.logger)
|
||||||
|
|
||||||
|
|
||||||
def test_fetch_until(sources: Sources, mocker: MockerFixture) -> None:
|
def test_fetch_until(sources: Sources, mocker: MockerFixture) -> None:
|
||||||
@ -450,10 +439,12 @@ def test_fetch_until(sources: Sources, mocker: MockerFixture) -> None:
|
|||||||
local = Path("local")
|
local = Path("local")
|
||||||
sources.fetch_until(local, branch="master", commit_sha="sha")
|
sources.fetch_until(local, branch="master", commit_sha="sha")
|
||||||
check_output_mock.assert_has_calls([
|
check_output_mock.assert_has_calls([
|
||||||
MockCall("git", "fetch", "--quiet", "--depth", "1", "origin", "master", cwd=local, logger=sources.logger),
|
MockCall(*sources.git(), "fetch", "--quiet", "--depth", "1", "origin", "master",
|
||||||
MockCall("git", "cat-file", "-e", "sha", cwd=local, logger=sources.logger),
|
cwd=local, logger=sources.logger),
|
||||||
MockCall("git", "fetch", "--quiet", "--depth", "2", "origin", "master", cwd=local, logger=sources.logger),
|
MockCall(*sources.git(), "cat-file", "-e", "sha", cwd=local, logger=sources.logger),
|
||||||
MockCall("git", "cat-file", "-e", "sha", cwd=local, logger=sources.logger),
|
MockCall(*sources.git(), "fetch", "--quiet", "--depth", "2", "origin", "master",
|
||||||
|
cwd=local, logger=sources.logger),
|
||||||
|
MockCall(*sources.git(), "cat-file", "-e", "sha", cwd=local, logger=sources.logger),
|
||||||
])
|
])
|
||||||
|
|
||||||
|
|
||||||
@ -466,8 +457,9 @@ def test_fetch_until_first(sources: Sources, mocker: MockerFixture) -> None:
|
|||||||
local = Path("local")
|
local = Path("local")
|
||||||
sources.fetch_until(local, branch="master")
|
sources.fetch_until(local, branch="master")
|
||||||
check_output_mock.assert_has_calls([
|
check_output_mock.assert_has_calls([
|
||||||
MockCall("git", "fetch", "--quiet", "--depth", "1", "origin", "master", cwd=local, logger=sources.logger),
|
MockCall(*sources.git(), "fetch", "--quiet", "--depth", "1", "origin", "master",
|
||||||
MockCall("git", "cat-file", "-e", "HEAD", cwd=local, logger=sources.logger),
|
cwd=local, logger=sources.logger),
|
||||||
|
MockCall(*sources.git(), "cat-file", "-e", "HEAD", cwd=local, logger=sources.logger),
|
||||||
])
|
])
|
||||||
|
|
||||||
|
|
||||||
@ -480,11 +472,27 @@ def test_fetch_until_all_branches(sources: Sources, mocker: MockerFixture) -> No
|
|||||||
local = Path("local")
|
local = Path("local")
|
||||||
sources.fetch_until(local)
|
sources.fetch_until(local)
|
||||||
check_output_mock.assert_has_calls([
|
check_output_mock.assert_has_calls([
|
||||||
MockCall("git", "fetch", "--quiet", "--depth", "1", cwd=local, logger=sources.logger),
|
MockCall(*sources.git(), "fetch", "--quiet", "--depth", "1", cwd=local, logger=sources.logger),
|
||||||
MockCall("git", "cat-file", "-e", "HEAD", cwd=local, logger=sources.logger),
|
MockCall(*sources.git(), "cat-file", "-e", "HEAD", cwd=local, logger=sources.logger),
|
||||||
])
|
])
|
||||||
|
|
||||||
|
|
||||||
|
def test_git(sources: Sources) -> None:
|
||||||
|
"""
|
||||||
|
must correctly generate git command
|
||||||
|
"""
|
||||||
|
assert sources.git() == ["git", "-c", "init.defaultBranch=\"master\""]
|
||||||
|
|
||||||
|
|
||||||
|
def test_git_overrides(sources: Sources) -> None:
|
||||||
|
"""
|
||||||
|
must correctly generate git command with additional settings
|
||||||
|
"""
|
||||||
|
assert sources.git({"user.email": "ahriman@localhost"}) == [
|
||||||
|
"git", "-c", "init.defaultBranch=\"master\"", "-c", "user.email=\"ahriman@localhost\""
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
def test_has_changes(sources: Sources, mocker: MockerFixture) -> None:
|
def test_has_changes(sources: Sources, mocker: MockerFixture) -> None:
|
||||||
"""
|
"""
|
||||||
must correctly identify if there are changes
|
must correctly identify if there are changes
|
||||||
@ -493,12 +501,12 @@ def test_has_changes(sources: Sources, mocker: MockerFixture) -> None:
|
|||||||
|
|
||||||
check_output_mock = mocker.patch("ahriman.core.build_tools.sources.check_output", return_value="M a.txt")
|
check_output_mock = mocker.patch("ahriman.core.build_tools.sources.check_output", return_value="M a.txt")
|
||||||
assert sources.has_changes(local)
|
assert sources.has_changes(local)
|
||||||
check_output_mock.assert_called_once_with("git", "diff", "--cached", "--name-only",
|
check_output_mock.assert_called_once_with(*sources.git(), "diff", "--cached", "--name-only",
|
||||||
cwd=local, logger=sources.logger)
|
cwd=local, logger=sources.logger)
|
||||||
|
|
||||||
check_output_mock = mocker.patch("ahriman.core.build_tools.sources.check_output", return_value="")
|
check_output_mock = mocker.patch("ahriman.core.build_tools.sources.check_output", return_value="")
|
||||||
assert not sources.has_changes(local)
|
assert not sources.has_changes(local)
|
||||||
check_output_mock.assert_called_once_with("git", "diff", "--cached", "--name-only",
|
check_output_mock.assert_called_once_with(*sources.git(), "diff", "--cached", "--name-only",
|
||||||
cwd=local, logger=sources.logger)
|
cwd=local, logger=sources.logger)
|
||||||
|
|
||||||
|
|
||||||
@ -510,7 +518,7 @@ def test_head(sources: Sources, mocker: MockerFixture) -> None:
|
|||||||
local = Path("local")
|
local = Path("local")
|
||||||
|
|
||||||
assert sources.head(local) == "sha"
|
assert sources.head(local) == "sha"
|
||||||
check_output_mock.assert_called_once_with("git", "rev-parse", "HEAD", cwd=local, logger=sources.logger)
|
check_output_mock.assert_called_once_with(*sources.git(), "rev-parse", "HEAD", cwd=local, logger=sources.logger)
|
||||||
|
|
||||||
|
|
||||||
def test_head_specific(sources: Sources, mocker: MockerFixture) -> None:
|
def test_head_specific(sources: Sources, mocker: MockerFixture) -> None:
|
||||||
@ -521,7 +529,7 @@ def test_head_specific(sources: Sources, mocker: MockerFixture) -> None:
|
|||||||
local = Path("local")
|
local = Path("local")
|
||||||
|
|
||||||
assert sources.head(local, "master") == "sha"
|
assert sources.head(local, "master") == "sha"
|
||||||
check_output_mock.assert_called_once_with("git", "rev-parse", "master", cwd=local, logger=sources.logger)
|
check_output_mock.assert_called_once_with(*sources.git(), "rev-parse", "master", cwd=local, logger=sources.logger)
|
||||||
|
|
||||||
|
|
||||||
def test_move(sources: Sources, mocker: MockerFixture) -> None:
|
def test_move(sources: Sources, mocker: MockerFixture) -> None:
|
||||||
@ -554,7 +562,7 @@ def test_patch_apply(sources: Sources, mocker: MockerFixture) -> None:
|
|||||||
local = Path("local")
|
local = Path("local")
|
||||||
sources.patch_apply(local, patch)
|
sources.patch_apply(local, patch)
|
||||||
check_output_mock.assert_called_once_with(
|
check_output_mock.assert_called_once_with(
|
||||||
"git", "apply", "--ignore-space-change", "--ignore-whitespace",
|
*sources.git(), "apply", "--ignore-space-change", "--ignore-whitespace",
|
||||||
cwd=local, input_data=patch.value, logger=sources.logger
|
cwd=local, input_data=patch.value, logger=sources.logger
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -7,6 +7,7 @@ from pytest_mock import MockerFixture
|
|||||||
from ahriman import __version__
|
from ahriman import __version__
|
||||||
from ahriman.core.alpm.pacman import Pacman
|
from ahriman.core.alpm.pacman import Pacman
|
||||||
from ahriman.core.alpm.remote import AUR
|
from ahriman.core.alpm.remote import AUR
|
||||||
|
from ahriman.core.configuration import Configuration
|
||||||
from ahriman.models.build_status import BuildStatus, BuildStatusEnum
|
from ahriman.models.build_status import BuildStatus, BuildStatusEnum
|
||||||
from ahriman.models.counters import Counters
|
from ahriman.models.counters import Counters
|
||||||
from ahriman.models.filesystem_package import FilesystemPackage
|
from ahriman.models.filesystem_package import FilesystemPackage
|
||||||
@ -17,6 +18,7 @@ from ahriman.models.package_description import PackageDescription
|
|||||||
from ahriman.models.package_source import PackageSource
|
from ahriman.models.package_source import PackageSource
|
||||||
from ahriman.models.remote_source import RemoteSource
|
from ahriman.models.remote_source import RemoteSource
|
||||||
from ahriman.models.repository_paths import RepositoryPaths
|
from ahriman.models.repository_paths import RepositoryPaths
|
||||||
|
from ahriman.models.scan_paths import ScanPaths
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
@ -77,7 +79,7 @@ def internal_status(counters: Counters) -> InternalStatus:
|
|||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def package_archive_ahriman(package_ahriman: Package, repository_paths: RepositoryPaths, pacman: Pacman,
|
def package_archive_ahriman(package_ahriman: Package, repository_paths: RepositoryPaths, pacman: Pacman,
|
||||||
passwd: Any, mocker: MockerFixture) -> PackageArchive:
|
scan_paths: ScanPaths, passwd: Any, mocker: MockerFixture) -> PackageArchive:
|
||||||
"""
|
"""
|
||||||
package archive fixture
|
package archive fixture
|
||||||
|
|
||||||
@ -85,6 +87,7 @@ def package_archive_ahriman(package_ahriman: Package, repository_paths: Reposito
|
|||||||
package_ahriman(Package): package test instance
|
package_ahriman(Package): package test instance
|
||||||
repository_paths(RepositoryPaths): repository paths test instance
|
repository_paths(RepositoryPaths): repository paths test instance
|
||||||
pacman(Pacman): pacman test instance
|
pacman(Pacman): pacman test instance
|
||||||
|
scan_paths(ScanPaths): scan paths test instance
|
||||||
passwd(Any): passwd structure test instance
|
passwd(Any): passwd structure test instance
|
||||||
mocker(MockerFixture): mocker object
|
mocker(MockerFixture): mocker object
|
||||||
|
|
||||||
@ -92,7 +95,7 @@ def package_archive_ahriman(package_ahriman: Package, repository_paths: Reposito
|
|||||||
PackageArchive: package archive test instance
|
PackageArchive: package archive test instance
|
||||||
"""
|
"""
|
||||||
mocker.patch("ahriman.models.repository_paths.getpwuid", return_value=passwd)
|
mocker.patch("ahriman.models.repository_paths.getpwuid", return_value=passwd)
|
||||||
return PackageArchive(repository_paths.build_directory, package_ahriman, pacman)
|
return PackageArchive(repository_paths.build_directory, package_ahriman, pacman, scan_paths)
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
@ -158,3 +161,20 @@ def pyalpm_package_description_ahriman(package_description_ahriman: PackageDescr
|
|||||||
type(mock).provides = PropertyMock(return_value=package_description_ahriman.provides)
|
type(mock).provides = PropertyMock(return_value=package_description_ahriman.provides)
|
||||||
type(mock).url = PropertyMock(return_value=package_description_ahriman.url)
|
type(mock).url = PropertyMock(return_value=package_description_ahriman.url)
|
||||||
return mock
|
return mock
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def scan_paths(configuration: Configuration) -> ScanPaths:
|
||||||
|
"""
|
||||||
|
scan paths fixture
|
||||||
|
|
||||||
|
Args:
|
||||||
|
configuration(Configuration): configuration test instance
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
ScanPaths: scan paths test instance
|
||||||
|
"""
|
||||||
|
return ScanPaths(
|
||||||
|
allowed_paths=configuration.getpathlist("build", "allowed_scan_paths"),
|
||||||
|
blacklisted_paths=configuration.getpathlist("build", "blacklisted_scan_paths"),
|
||||||
|
)
|
||||||
|
@ -134,8 +134,10 @@ def test_refine_dependencies(package_archive_ahriman: PackageArchive, mocker: Mo
|
|||||||
|
|
||||||
path1 = Path("usr") / "lib" / "python3.12"
|
path1 = Path("usr") / "lib" / "python3.12"
|
||||||
path2 = path1 / "site-packages"
|
path2 = path1 / "site-packages"
|
||||||
path3 = Path("etc")
|
path3 = Path("usr") / "lib" / "path"
|
||||||
path4 = Path("var") / "lib" / "whatever"
|
path4 = Path("usr") / "lib" / "whatever"
|
||||||
|
path5 = Path("usr") / "share" / "applications"
|
||||||
|
path6 = Path("etc")
|
||||||
|
|
||||||
package1 = FilesystemPackage(package_name="package1", depends={"package5"}, opt_depends={"package2"})
|
package1 = FilesystemPackage(package_name="package1", depends={"package5"}, opt_depends={"package2"})
|
||||||
package2 = FilesystemPackage(package_name="package2", depends={"package1"}, opt_depends=set())
|
package2 = FilesystemPackage(package_name="package2", depends={"package1"}, opt_depends=set())
|
||||||
@ -149,6 +151,8 @@ def test_refine_dependencies(package_archive_ahriman: PackageArchive, mocker: Mo
|
|||||||
path2: [package1, package2, package3, package5],
|
path2: [package1, package2, package3, package5],
|
||||||
path3: [package1, package4],
|
path3: [package1, package4],
|
||||||
path4: [package1],
|
path4: [package1],
|
||||||
|
path5: [package1],
|
||||||
|
path6: [package1],
|
||||||
}) == {
|
}) == {
|
||||||
path1: [package6],
|
path1: [package6],
|
||||||
path2: [package1, package5],
|
path2: [package1, package5],
|
||||||
|
42
tests/ahriman/models/test_scan_paths.py
Normal file
42
tests/ahriman/models/test_scan_paths.py
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
from ahriman.models.scan_paths import ScanPaths
|
||||||
|
|
||||||
|
|
||||||
|
def test_post_init(scan_paths: ScanPaths) -> None:
|
||||||
|
"""
|
||||||
|
must convert paths to / relative
|
||||||
|
"""
|
||||||
|
assert all(not path.is_absolute() for path in scan_paths.allowed_paths)
|
||||||
|
assert all(not path.is_absolute() for path in scan_paths.blacklisted_paths)
|
||||||
|
|
||||||
|
|
||||||
|
def test_is_allowed() -> None:
|
||||||
|
"""
|
||||||
|
must check if path is subpath of one in allowed list
|
||||||
|
"""
|
||||||
|
assert ScanPaths(allowed_paths=[Path("/") / "usr"], blacklisted_paths=[]).is_allowed(Path("usr"))
|
||||||
|
assert ScanPaths(allowed_paths=[Path("/") / "usr"], blacklisted_paths=[]).is_allowed(Path("usr") / "lib")
|
||||||
|
assert not ScanPaths(allowed_paths=[Path("/") / "usr"], blacklisted_paths=[]).is_allowed(Path("var"))
|
||||||
|
|
||||||
|
|
||||||
|
def test_is_blacklisted() -> None:
|
||||||
|
"""
|
||||||
|
must check if path is not subpath of one in blacklist
|
||||||
|
"""
|
||||||
|
assert ScanPaths(
|
||||||
|
allowed_paths=[Path("/") / "usr"],
|
||||||
|
blacklisted_paths=[Path("/") / "usr" / "lib"],
|
||||||
|
).is_allowed(Path("usr"))
|
||||||
|
assert ScanPaths(
|
||||||
|
allowed_paths=[Path("/") / "usr", Path("/") / "var"],
|
||||||
|
blacklisted_paths=[Path("/") / "usr" / "lib"],
|
||||||
|
).is_allowed(Path("var"))
|
||||||
|
assert not ScanPaths(
|
||||||
|
allowed_paths=[Path("/") / "usr"],
|
||||||
|
blacklisted_paths=[Path("/") / "usr" / "lib"],
|
||||||
|
).is_allowed(Path(" usr") / "lib")
|
||||||
|
assert not ScanPaths(
|
||||||
|
allowed_paths=[Path("/") / "usr"],
|
||||||
|
blacklisted_paths=[Path("/") / "usr" / "lib"],
|
||||||
|
).is_allowed(Path("usr") / "lib" / "qt")
|
@ -20,7 +20,9 @@ salt = salt
|
|||||||
allow_read_only = no
|
allow_read_only = no
|
||||||
|
|
||||||
[build]
|
[build]
|
||||||
|
allowed_scan_paths = /usr/lib
|
||||||
archbuild_flags =
|
archbuild_flags =
|
||||||
|
blacklisted_scan_paths = /usr/lib/cmake
|
||||||
build_command = extra-x86_64-build
|
build_command = extra-x86_64-build
|
||||||
ignore_packages =
|
ignore_packages =
|
||||||
makechrootpkg_flags =
|
makechrootpkg_flags =
|
||||||
|
Loading…
x
Reference in New Issue
Block a user