mirror of
https://github.com/arcan1s/ahriman.git
synced 2025-04-24 15:27:17 +00:00
implement single-function patches (#69)
This commit is contained in:
parent
ad7cdb7d95
commit
649df81aa5
@ -3,7 +3,7 @@
|
|||||||
ahriman
|
ahriman
|
||||||
.SH SYNOPSIS
|
.SH SYNOPSIS
|
||||||
.B ahriman
|
.B ahriman
|
||||||
[-h] [-a ARCHITECTURE] [-c CONFIGURATION] [--force] [-l LOCK] [--no-report] [-q] [--unsafe] [-V] {aur-search,search,help,help-commands-unsafe,key-import,package-add,add,package-update,package-remove,remove,package-status,status,package-status-remove,package-status-update,status-update,patch-add,patch-list,patch-remove,repo-backup,repo-check,check,repo-clean,clean,repo-config,config,repo-rebuild,rebuild,repo-remove-unknown,remove-unknown,repo-report,report,repo-restore,repo-setup,init,repo-init,setup,repo-sign,sign,repo-status-update,repo-sync,sync,repo-triggers,repo-update,update,shell,user-add,user-list,user-remove,version,web} ...
|
[-h] [-a ARCHITECTURE] [-c CONFIGURATION] [--force] [-l LOCK] [--no-report] [-q] [--unsafe] [-V] {aur-search,search,help,help-commands-unsafe,key-import,package-add,add,package-update,package-remove,remove,package-status,status,package-status-remove,package-status-update,status-update,patch-add,patch-list,patch-remove,patch-set-add,repo-backup,repo-check,check,repo-clean,clean,repo-config,config,repo-rebuild,rebuild,repo-remove-unknown,remove-unknown,repo-report,report,repo-restore,repo-setup,init,repo-init,setup,repo-sign,sign,repo-status-update,repo-sync,sync,repo-triggers,repo-update,update,shell,user-add,user-list,user-remove,version,web} ...
|
||||||
.SH DESCRIPTION
|
.SH DESCRIPTION
|
||||||
ArcH linux ReposItory MANager
|
ArcH linux ReposItory MANager
|
||||||
|
|
||||||
@ -71,7 +71,7 @@ remove package status
|
|||||||
update package status
|
update package status
|
||||||
.TP
|
.TP
|
||||||
\fBahriman\fR \fI\,patch-add\/\fR
|
\fBahriman\fR \fI\,patch-add\/\fR
|
||||||
add patch set
|
add patch for PKGBUILD function
|
||||||
.TP
|
.TP
|
||||||
\fBahriman\fR \fI\,patch-list\/\fR
|
\fBahriman\fR \fI\,patch-list\/\fR
|
||||||
list patch sets
|
list patch sets
|
||||||
@ -79,6 +79,9 @@ list patch sets
|
|||||||
\fBahriman\fR \fI\,patch-remove\/\fR
|
\fBahriman\fR \fI\,patch-remove\/\fR
|
||||||
remove patch set
|
remove patch set
|
||||||
.TP
|
.TP
|
||||||
|
\fBahriman\fR \fI\,patch-set-add\/\fR
|
||||||
|
add patch set
|
||||||
|
.TP
|
||||||
\fBahriman\fR \fI\,repo-backup\/\fR
|
\fBahriman\fR \fI\,repo-backup\/\fR
|
||||||
backup repository data
|
backup repository data
|
||||||
.TP
|
.TP
|
||||||
@ -284,21 +287,25 @@ set status for specified packages. If no packages supplied, service status will
|
|||||||
new status
|
new status
|
||||||
|
|
||||||
.SH COMMAND \fI\,'ahriman patch-add'\/\fR
|
.SH COMMAND \fI\,'ahriman patch-add'\/\fR
|
||||||
usage: ahriman patch-add [-h] [-t TRACK] package
|
usage: ahriman patch-add [-h] [-p PATCH] package variable
|
||||||
|
|
||||||
create or update source patches
|
create or update patched PKGBUILD function or variable
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
\fBpackage\fR
|
\fBpackage\fR
|
||||||
path to directory with changed files for patch addition/update
|
package base
|
||||||
|
|
||||||
|
.TP
|
||||||
|
\fBvariable\fR
|
||||||
|
PKGBUILD variable or function name. If variable is a function, it must end with ()
|
||||||
|
|
||||||
.SH OPTIONS \fI\,'ahriman patch-add'\/\fR
|
.SH OPTIONS \fI\,'ahriman patch-add'\/\fR
|
||||||
.TP
|
.TP
|
||||||
\fB\-t\fR \fI\,TRACK\/\fR, \fB\-\-track\fR \fI\,TRACK\/\fR
|
\fB\-p\fR \fI\,PATCH\/\fR, \fB\-\-patch\fR \fI\,PATCH\/\fR
|
||||||
files which has to be tracked
|
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] [package]
|
usage: ahriman patch-list [-h] [-e] [-v VARIABLE] [package]
|
||||||
|
|
||||||
list available patches for the package
|
list available patches for the package
|
||||||
|
|
||||||
@ -311,8 +318,12 @@ package base
|
|||||||
\fB\-e\fR, \fB\-\-exit\-code\fR
|
\fB\-e\fR, \fB\-\-exit\-code\fR
|
||||||
return non\-zero exit status if result is empty
|
return non\-zero exit status if result is empty
|
||||||
|
|
||||||
|
.TP
|
||||||
|
\fB\-v\fR \fI\,VARIABLE\/\fR, \fB\-\-variable\fR \fI\,VARIABLE\/\fR
|
||||||
|
if set, show only patches for specified PKGBUILD variables
|
||||||
|
|
||||||
.SH COMMAND \fI\,'ahriman patch-remove'\/\fR
|
.SH COMMAND \fI\,'ahriman patch-remove'\/\fR
|
||||||
usage: ahriman patch-remove [-h] package
|
usage: ahriman patch-remove [-h] [-v VARIABLE] package
|
||||||
|
|
||||||
remove patches for the package
|
remove patches for the package
|
||||||
|
|
||||||
@ -320,6 +331,26 @@ remove patches for the package
|
|||||||
\fBpackage\fR
|
\fBpackage\fR
|
||||||
package base
|
package base
|
||||||
|
|
||||||
|
.SH OPTIONS \fI\,'ahriman patch-remove'\/\fR
|
||||||
|
.TP
|
||||||
|
\fB\-v\fR \fI\,VARIABLE\/\fR, \fB\-\-variable\fR \fI\,VARIABLE\/\fR
|
||||||
|
should be used for single\-function patches in case if you wold like to remove only specified PKGBUILD variables. In case
|
||||||
|
if not set, it will remove all patches related to the package
|
||||||
|
|
||||||
|
.SH COMMAND \fI\,'ahriman patch-set-add'\/\fR
|
||||||
|
usage: ahriman patch-set-add [-h] [-t TRACK] package
|
||||||
|
|
||||||
|
create or update source patches
|
||||||
|
|
||||||
|
.TP
|
||||||
|
\fBpackage\fR
|
||||||
|
path to directory with changed files for patch addition/update
|
||||||
|
|
||||||
|
.SH OPTIONS \fI\,'ahriman patch-set-add'\/\fR
|
||||||
|
.TP
|
||||||
|
\fB\-t\fR \fI\,TRACK\/\fR, \fB\-\-track\fR \fI\,TRACK\/\fR
|
||||||
|
files which has to be tracked
|
||||||
|
|
||||||
.SH COMMAND \fI\,'ahriman repo-backup'\/\fR
|
.SH COMMAND \fI\,'ahriman repo-backup'\/\fR
|
||||||
usage: ahriman repo-backup [-h] path
|
usage: ahriman repo-backup [-h] path
|
||||||
|
|
||||||
|
@ -28,6 +28,14 @@ ahriman.core.database.migrations.m002\_user\_access module
|
|||||||
:no-undoc-members:
|
:no-undoc-members:
|
||||||
:show-inheritance:
|
:show-inheritance:
|
||||||
|
|
||||||
|
ahriman.core.database.migrations.m003\_patch\_variables module
|
||||||
|
--------------------------------------------------------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.core.database.migrations.m003_patch_variables
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
|
||||||
Module contents
|
Module contents
|
||||||
---------------
|
---------------
|
||||||
|
|
||||||
|
@ -36,6 +36,14 @@ ahriman.core.formatters.package\_printer module
|
|||||||
:no-undoc-members:
|
:no-undoc-members:
|
||||||
:show-inheritance:
|
:show-inheritance:
|
||||||
|
|
||||||
|
ahriman.core.formatters.patch\_printer module
|
||||||
|
---------------------------------------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.core.formatters.patch_printer
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
|
||||||
ahriman.core.formatters.printer module
|
ahriman.core.formatters.printer module
|
||||||
--------------------------------------
|
--------------------------------------
|
||||||
|
|
||||||
|
@ -162,11 +162,13 @@ Unlike ``RemotePullTrigger`` trigger, the ``RemotePushTrigger`` more likely will
|
|||||||
But I just wanted to change PKGBUILD from AUR a bit!
|
But I just wanted to change PKGBUILD from AUR a bit!
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
Well it is supported also.
|
Well it is supported also. The recommended way is to patch specific function, e.g. by running ``sudo -u ahriman ahriman patch-add ahriman version``. This command will prompt for new value of the PKGBUILD variable ``version``. You can also write it to file and read from it ``sudo -u ahriman ahriman patch-add ahriman version version.patch``.
|
||||||
|
|
||||||
|
Alternatively you can create full-diff patches, which are calculated by using ``git diff`` from current PKGBUILD master branch:
|
||||||
|
|
||||||
#. Clone sources from AUR.
|
#. Clone sources from AUR.
|
||||||
#. Make changes you would like to (e.g. edit ``PKGBUILD``, add external patches).
|
#. Make changes you would like to (e.g. edit ``PKGBUILD``, add external patches).
|
||||||
#. Run ``sudo -u ahriman ahriman patch-add /path/to/local/directory/with/PKGBUILD``.
|
#. Run ``sudo -u ahriman ahriman patch-set-add /path/to/local/directory/with/PKGBUILD``.
|
||||||
|
|
||||||
The last command will calculate diff from current tree to the ``HEAD`` and will store it locally. Patches will be applied on any package actions (e.g. it can be used for dependency management).
|
The last command will calculate diff from current tree to the ``HEAD`` and will store it locally. Patches will be applied on any package actions (e.g. it can be used for dependency management).
|
||||||
|
|
||||||
|
@ -93,6 +93,7 @@ def _parser() -> argparse.ArgumentParser:
|
|||||||
_set_patch_add_parser(subparsers)
|
_set_patch_add_parser(subparsers)
|
||||||
_set_patch_list_parser(subparsers)
|
_set_patch_list_parser(subparsers)
|
||||||
_set_patch_remove_parser(subparsers)
|
_set_patch_remove_parser(subparsers)
|
||||||
|
_set_patch_set_add_parser(subparsers)
|
||||||
_set_repo_backup_parser(subparsers)
|
_set_repo_backup_parser(subparsers)
|
||||||
_set_repo_check_parser(subparsers)
|
_set_repo_check_parser(subparsers)
|
||||||
_set_repo_clean_parser(subparsers)
|
_set_repo_clean_parser(subparsers)
|
||||||
@ -320,7 +321,7 @@ def _set_package_status_update_parser(root: SubParserAction) -> argparse.Argumen
|
|||||||
|
|
||||||
def _set_patch_add_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
def _set_patch_add_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
||||||
"""
|
"""
|
||||||
add parser for new patch subcommand
|
add parser for new single-function patch subcommand
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
root(SubParserAction): subparsers for the commands
|
root(SubParserAction): subparsers for the commands
|
||||||
@ -328,16 +329,18 @@ def _set_patch_add_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
|||||||
Returns:
|
Returns:
|
||||||
argparse.ArgumentParser: created argument parser
|
argparse.ArgumentParser: created argument parser
|
||||||
"""
|
"""
|
||||||
parser = root.add_parser("patch-add", help="add patch set", description="create or update source patches",
|
parser = root.add_parser("patch-add", help="add patch for PKGBUILD function",
|
||||||
epilog="In order to add a patch set for the package you will need to clone "
|
description="create or update patched PKGBUILD function or variable",
|
||||||
"the AUR package manually, add required changes (e.g. external patches, "
|
epilog="Unlike ``patch-set-add``, this function allows to patch only one PKGBUILD f"
|
||||||
"edit PKGBUILD) and run command, e.g. ``ahriman patch path/to/directory``. "
|
"unction, e.g. typing ``ahriman patch-add ahriman version`` it will change the "
|
||||||
"By default it tracks *.patch and *.diff files, but this behavior can be changed "
|
"``version`` inside PKGBUILD, typing ``ahriman patch-add ahriman build()`` "
|
||||||
"by using --track option",
|
"it will change ``build()`` function inside PKGBUILD",
|
||||||
formatter_class=_formatter)
|
formatter_class=_formatter)
|
||||||
parser.add_argument("package", help="path to directory with changed files for patch addition/update")
|
parser.add_argument("package", help="package base")
|
||||||
parser.add_argument("-t", "--track", help="files which has to be tracked", action="append",
|
parser.add_argument("variable", help="PKGBUILD variable or function name. If variable is a function, "
|
||||||
default=["*.diff", "*.patch"])
|
"it must end with ()")
|
||||||
|
parser.add_argument("patch", help="path to file which contains function or variable value. If not set, "
|
||||||
|
"the value will be read from stdin", type=Path, nargs="?")
|
||||||
parser.set_defaults(handler=handlers.Patch, action=Action.Update, architecture=[""], lock=None, no_report=True)
|
parser.set_defaults(handler=handlers.Patch, action=Action.Update, architecture=[""], lock=None, no_report=True)
|
||||||
return parser
|
return parser
|
||||||
|
|
||||||
@ -356,6 +359,8 @@ def _set_patch_list_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
|||||||
description="list available patches for the package", formatter_class=_formatter)
|
description="list available patches for the package", formatter_class=_formatter)
|
||||||
parser.add_argument("package", help="package base", nargs="?")
|
parser.add_argument("package", help="package base", nargs="?")
|
||||||
parser.add_argument("-e", "--exit-code", help="return non-zero exit status if result is empty", action="store_true")
|
parser.add_argument("-e", "--exit-code", help="return non-zero exit status if result is empty", action="store_true")
|
||||||
|
parser.add_argument("-v", "--variable", help="if set, show only patches for specified PKGBUILD variables",
|
||||||
|
action="append")
|
||||||
parser.set_defaults(handler=handlers.Patch, action=Action.List, architecture=[""], lock=None, no_report=True)
|
parser.set_defaults(handler=handlers.Patch, action=Action.List, architecture=[""], lock=None, no_report=True)
|
||||||
return parser
|
return parser
|
||||||
|
|
||||||
@ -373,10 +378,39 @@ def _set_patch_remove_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
|||||||
parser = root.add_parser("patch-remove", help="remove patch set", description="remove patches for the package",
|
parser = root.add_parser("patch-remove", help="remove patch set", description="remove patches for the package",
|
||||||
formatter_class=_formatter)
|
formatter_class=_formatter)
|
||||||
parser.add_argument("package", help="package base")
|
parser.add_argument("package", help="package base")
|
||||||
|
parser.add_argument("-v", "--variable", help="should be used for single-function patches in case if you wold like "
|
||||||
|
"to remove only specified PKGBUILD variables. In case if not set, "
|
||||||
|
"it will remove all patches related to the package",
|
||||||
|
action="append")
|
||||||
parser.set_defaults(handler=handlers.Patch, action=Action.Remove, architecture=[""], lock=None, no_report=True)
|
parser.set_defaults(handler=handlers.Patch, action=Action.Remove, architecture=[""], lock=None, no_report=True)
|
||||||
return parser
|
return parser
|
||||||
|
|
||||||
|
|
||||||
|
def _set_patch_set_add_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
||||||
|
"""
|
||||||
|
add parser for new full-diff patch subcommand
|
||||||
|
|
||||||
|
Args:
|
||||||
|
root(SubParserAction): subparsers for the commands
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
argparse.ArgumentParser: created argument parser
|
||||||
|
"""
|
||||||
|
parser = root.add_parser("patch-set-add", help="add patch set", description="create or update source patches",
|
||||||
|
epilog="In order to add a patch set for the package you will need to clone "
|
||||||
|
"the AUR package manually, add required changes (e.g. external patches, "
|
||||||
|
"edit PKGBUILD) and run command, e.g. ``ahriman patch-set-add path/to/directory``. "
|
||||||
|
"By default it tracks *.patch and *.diff files, but this behavior can be changed "
|
||||||
|
"by using --track option",
|
||||||
|
formatter_class=_formatter)
|
||||||
|
parser.add_argument("package", help="path to directory with changed files for patch addition/update", type=Path)
|
||||||
|
parser.add_argument("-t", "--track", help="files which has to be tracked", action="append",
|
||||||
|
default=["*.diff", "*.patch"])
|
||||||
|
parser.set_defaults(handler=handlers.Patch, action=Action.Update, architecture=[""], lock=None, no_report=True,
|
||||||
|
variable=None)
|
||||||
|
return parser
|
||||||
|
|
||||||
|
|
||||||
def _set_repo_backup_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
def _set_repo_backup_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
||||||
"""
|
"""
|
||||||
add parser for repository backup subcommand
|
add parser for repository backup subcommand
|
||||||
|
@ -18,17 +18,19 @@
|
|||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
#
|
#
|
||||||
import argparse
|
import argparse
|
||||||
|
import sys
|
||||||
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import List, Optional, Type
|
from typing import List, Optional, Tuple, Type
|
||||||
|
|
||||||
from ahriman.application.application import Application
|
from ahriman.application.application import Application
|
||||||
from ahriman.application.handlers import Handler
|
from ahriman.application.handlers import Handler
|
||||||
from ahriman.core.build_tools.sources import Sources
|
from ahriman.core.build_tools.sources import Sources
|
||||||
from ahriman.core.configuration import Configuration
|
from ahriman.core.configuration import Configuration
|
||||||
from ahriman.core.formatters import StringPrinter
|
from ahriman.core.formatters import PatchPrinter
|
||||||
from ahriman.models.action import Action
|
from ahriman.models.action import Action
|
||||||
from ahriman.models.package import Package
|
from ahriman.models.package import Package
|
||||||
|
from ahriman.models.pkgbuild_patch import PkgbuildPatch
|
||||||
|
|
||||||
|
|
||||||
class Patch(Handler):
|
class Patch(Handler):
|
||||||
@ -52,51 +54,93 @@ class Patch(Handler):
|
|||||||
application = Application(architecture, configuration, no_report, unsafe)
|
application = Application(architecture, configuration, no_report, unsafe)
|
||||||
application.on_start()
|
application.on_start()
|
||||||
|
|
||||||
if args.action == Action.List:
|
if args.action == Action.Update and args.variable is not None:
|
||||||
Patch.patch_set_list(application, args.package, args.exit_code)
|
patch = Patch.patch_create_from_function(args.variable, args.patch)
|
||||||
|
Patch.patch_set_create(application, args.package, patch)
|
||||||
|
elif args.action == Action.Update and args.variable is None:
|
||||||
|
package_base, patch = Patch.patch_create_from_diff(args.package, args.track)
|
||||||
|
Patch.patch_set_create(application, package_base, patch)
|
||||||
|
elif args.action == Action.List:
|
||||||
|
Patch.patch_set_list(application, args.package, args.variable, args.exit_code)
|
||||||
elif args.action == Action.Remove:
|
elif args.action == Action.Remove:
|
||||||
Patch.patch_set_remove(application, args.package)
|
Patch.patch_set_remove(application, args.package, args.variable)
|
||||||
elif args.action == Action.Update:
|
|
||||||
Patch.patch_set_create(application, Path(args.package), args.track)
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def patch_set_create(application: Application, sources_dir: Path, track: List[str]) -> None:
|
def patch_create_from_diff(sources_dir: Path, track: List[str]) -> Tuple[str, PkgbuildPatch]:
|
||||||
|
"""
|
||||||
|
create PKGBUILD plain diff patches from sources directory
|
||||||
|
|
||||||
|
Args:
|
||||||
|
sources_dir(Path): path to directory with the package sources
|
||||||
|
track(List[str]): track files which match the glob before creating the patch
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Tuple[str, PkgbuildPatch]: package base and created PKGBUILD patch based on the diff from master HEAD
|
||||||
|
to current files
|
||||||
|
"""
|
||||||
|
package = Package.from_build(sources_dir)
|
||||||
|
patch = Sources.patch_create(sources_dir, *track)
|
||||||
|
return package.base, PkgbuildPatch(None, patch)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def patch_create_from_function(variable: str, patch_path: Optional[Path]) -> PkgbuildPatch:
|
||||||
|
"""
|
||||||
|
create single-function patch set for the package base
|
||||||
|
|
||||||
|
Args:
|
||||||
|
variable(str): function or variable name inside PKGBUILD
|
||||||
|
patch_path(Path): optional path to patch content. If not set, it will be read from stdin
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
PkgbuildPatch: created patch for the PKGBUILD function
|
||||||
|
"""
|
||||||
|
if patch_path is None:
|
||||||
|
print("Post new function or variable value below. Press Ctrl-D to finish:", file=sys.stderr)
|
||||||
|
patch = "".join(list(sys.stdin))
|
||||||
|
else:
|
||||||
|
patch = patch_path.read_text(encoding="utf8")
|
||||||
|
patch = patch.strip() # remove spaces around the patch
|
||||||
|
return PkgbuildPatch(variable, patch)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def patch_set_create(application: Application, package_base: str, patch: PkgbuildPatch) -> None:
|
||||||
"""
|
"""
|
||||||
create patch set for the package base
|
create patch set for the package base
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
application(Application): application instance
|
application(Application): application instance
|
||||||
sources_dir(Path): path to directory with the package sources
|
package_base(str): package base
|
||||||
track(List[str]): track files which match the glob before creating the patch
|
patch(PkgbuildPatch): patch descriptor
|
||||||
"""
|
"""
|
||||||
package = Package.from_build(sources_dir)
|
application.database.patches_insert(package_base, patch)
|
||||||
patch = Sources.patch_create(sources_dir, *track)
|
|
||||||
application.database.patches_insert(package.base, patch)
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def patch_set_list(application: Application, package_base: Optional[str], exit_code: bool) -> None:
|
def patch_set_list(application: Application, package_base: Optional[str], variables: List[str],
|
||||||
|
exit_code: bool) -> None:
|
||||||
"""
|
"""
|
||||||
list patches available for the package base
|
list patches available for the package base
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
application(Application): application instance
|
application(Application): application instance
|
||||||
package_base(Optional[str]): package base
|
package_base(Optional[str]): package base
|
||||||
|
variables(List[str]): extract patches only for specified PKGBUILD variables
|
||||||
exit_code(bool): exit with error on empty search result
|
exit_code(bool): exit with error on empty search result
|
||||||
|
:
|
||||||
"""
|
"""
|
||||||
patches = application.database.patches_list(package_base)
|
patches = application.database.patches_list(package_base, variables)
|
||||||
Patch.check_if_empty(exit_code, not patches)
|
Patch.check_if_empty(exit_code, not patches)
|
||||||
|
|
||||||
for base, patch in patches.items():
|
for base, patch in patches.items():
|
||||||
content = base if package_base is None else patch
|
PatchPrinter(base, patch).print(verbose=True, separator=" = ")
|
||||||
StringPrinter(content).print(verbose=True)
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def patch_set_remove(application: Application, package_base: str) -> None:
|
def patch_set_remove(application: Application, package_base: str, variables: List[str]) -> None:
|
||||||
"""
|
"""
|
||||||
remove patch set for the package base
|
remove patch set for the package base
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
application(Application): application instance
|
application(Application): application instance
|
||||||
package_base(str): package base
|
package_base(str): package base
|
||||||
|
variables(List[str]): remove patches only for specified PKGBUILD variables
|
||||||
"""
|
"""
|
||||||
application.database.patches_remove(package_base)
|
application.database.patches_remove(package_base, variables)
|
||||||
|
@ -45,24 +45,22 @@ class Sources(LazyLogging):
|
|||||||
_check_output = check_output
|
_check_output = check_output
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def extend_architectures(sources_dir: Path, architecture: str) -> None:
|
def extend_architectures(sources_dir: Path, architecture: str) -> List[PkgbuildPatch]:
|
||||||
"""
|
"""
|
||||||
extend existing PKGBUILD with repository architecture
|
extend existing PKGBUILD with repository architecture
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
sources_dir(Path): local path to directory with source files
|
sources_dir(Path): local path to directory with source files
|
||||||
architecture(str): repository architecture
|
architecture(str): repository architecture
|
||||||
"""
|
|
||||||
pkgbuild_path = sources_dir / "PKGBUILD"
|
|
||||||
if not pkgbuild_path.is_file():
|
|
||||||
return
|
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
List[PkgbuildPatch]: generated patch for PKGBUILD architectures if required
|
||||||
|
"""
|
||||||
architectures = Package.supported_architectures(sources_dir)
|
architectures = Package.supported_architectures(sources_dir)
|
||||||
if "any" in architectures: # makepkg does not like when there is any other arch except for any
|
if "any" in architectures: # makepkg does not like when there is any other arch except for any
|
||||||
return
|
return []
|
||||||
architectures.add(architecture)
|
architectures.add(architecture)
|
||||||
patch = PkgbuildPatch("arch", list(architectures))
|
return [PkgbuildPatch("arch", list(architectures))]
|
||||||
patch.write(pkgbuild_path)
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def fetch(sources_dir: Path, remote: Optional[RemoteSource]) -> None:
|
def fetch(sources_dir: Path, remote: Optional[RemoteSource]) -> None:
|
||||||
@ -134,14 +132,14 @@ class Sources(LazyLogging):
|
|||||||
exception=None, cwd=sources_dir, logger=instance.logger)
|
exception=None, cwd=sources_dir, logger=instance.logger)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def load(sources_dir: Path, package: Package, patch: Optional[str], paths: RepositoryPaths) -> None:
|
def load(sources_dir: Path, package: Package, patches: List[PkgbuildPatch], paths: RepositoryPaths) -> None:
|
||||||
"""
|
"""
|
||||||
fetch sources from remote and apply patches
|
fetch sources from remote and apply patches
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
sources_dir(Path): local path to fetch
|
sources_dir(Path): local path to fetch
|
||||||
package(Package): package definitions
|
package(Package): package definitions
|
||||||
patch(Optional[str]): optional patch to be applied
|
patches(List[PkgbuildPatch]): optional patch to be applied
|
||||||
paths(RepositoryPaths): repository paths instance
|
paths(RepositoryPaths): repository paths instance
|
||||||
"""
|
"""
|
||||||
instance = Sources()
|
instance = Sources()
|
||||||
@ -150,9 +148,9 @@ class Sources(LazyLogging):
|
|||||||
shutil.copytree(cache_dir, sources_dir, dirs_exist_ok=True)
|
shutil.copytree(cache_dir, sources_dir, dirs_exist_ok=True)
|
||||||
instance.fetch(sources_dir, package.remote)
|
instance.fetch(sources_dir, package.remote)
|
||||||
|
|
||||||
if patch is not None:
|
patches.extend(instance.extend_architectures(sources_dir, paths.architecture))
|
||||||
|
for patch in patches:
|
||||||
instance.patch_apply(sources_dir, patch)
|
instance.patch_apply(sources_dir, patch)
|
||||||
instance.extend_architectures(sources_dir, paths.architecture)
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def patch_create(sources_dir: Path, *pattern: str) -> str:
|
def patch_create(sources_dir: Path, *pattern: str) -> str:
|
||||||
@ -248,15 +246,18 @@ class Sources(LazyLogging):
|
|||||||
dst = sources_dir / src.relative_to(pkgbuild_dir)
|
dst = sources_dir / src.relative_to(pkgbuild_dir)
|
||||||
shutil.move(src, dst)
|
shutil.move(src, dst)
|
||||||
|
|
||||||
def patch_apply(self, sources_dir: Path, patch: str) -> None:
|
def patch_apply(self, sources_dir: Path, patch: PkgbuildPatch) -> None:
|
||||||
"""
|
"""
|
||||||
apply patches if any
|
apply patches if any
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
sources_dir(Path): local path to directory with git sources
|
sources_dir(Path): local path to directory with git sources
|
||||||
patch(str): patch to be applied
|
patch(PkgbuildPatch): patch to be applied
|
||||||
"""
|
"""
|
||||||
# create patch
|
# create patch
|
||||||
self.logger.info("apply patch from database")
|
self.logger.info("apply patch %s from database at %s", patch.key, sources_dir)
|
||||||
Sources._check_output("git", "apply", "--ignore-space-change", "--ignore-whitespace",
|
if patch.is_plain_diff:
|
||||||
exception=None, cwd=sources_dir, input_data=patch, logger=self.logger)
|
Sources._check_output("git", "apply", "--ignore-space-change", "--ignore-whitespace",
|
||||||
|
exception=None, cwd=sources_dir, input_data=patch.serialize(), logger=self.logger)
|
||||||
|
else:
|
||||||
|
patch.write(sources_dir / "PKGBUILD")
|
||||||
|
43
src/ahriman/core/database/migrations/m003_patch_variables.py
Normal file
43
src/ahriman/core/database/migrations/m003_patch_variables.py
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
#
|
||||||
|
# Copyright (c) 2021-2022 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/>.
|
||||||
|
#
|
||||||
|
__all__ = ["steps"]
|
||||||
|
|
||||||
|
|
||||||
|
steps = [
|
||||||
|
"""
|
||||||
|
alter table patches rename to patches_
|
||||||
|
""",
|
||||||
|
"""
|
||||||
|
create table patches (
|
||||||
|
package_base text not null,
|
||||||
|
variable text,
|
||||||
|
patch blob not null
|
||||||
|
)
|
||||||
|
""",
|
||||||
|
"""
|
||||||
|
create unique index patches_package_base_variable on patches (package_base, coalesce(variable, ''))
|
||||||
|
""",
|
||||||
|
"""
|
||||||
|
insert into patches (package_base, patch) select package_base, patch from patches_
|
||||||
|
""",
|
||||||
|
"""
|
||||||
|
drop table patches_
|
||||||
|
""",
|
||||||
|
]
|
@ -17,10 +17,13 @@
|
|||||||
# 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/>.
|
||||||
#
|
#
|
||||||
|
from collections import defaultdict
|
||||||
|
|
||||||
from sqlite3 import Connection
|
from sqlite3 import Connection
|
||||||
from typing import Dict, Optional
|
from typing import Dict, List, Optional, Tuple
|
||||||
|
|
||||||
from ahriman.core.database.operations import Operations
|
from ahriman.core.database.operations import Operations
|
||||||
|
from ahriman.models.pkgbuild_patch import PkgbuildPatch
|
||||||
|
|
||||||
|
|
||||||
class PatchOperations(Operations):
|
class PatchOperations(Operations):
|
||||||
@ -28,7 +31,7 @@ class PatchOperations(Operations):
|
|||||||
operations for patches
|
operations for patches
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def patches_get(self, package_base: str) -> Optional[str]:
|
def patches_get(self, package_base: str) -> List[PkgbuildPatch]:
|
||||||
"""
|
"""
|
||||||
retrieve patches for the package
|
retrieve patches for the package
|
||||||
|
|
||||||
@ -36,62 +39,77 @@ class PatchOperations(Operations):
|
|||||||
package_base(str): package base to search for patches
|
package_base(str): package base to search for patches
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Optional[str]: plain text patch for the package
|
List[PkgbuildPatch]: plain text patch for the package
|
||||||
"""
|
"""
|
||||||
return self.patches_list(package_base).get(package_base)
|
return self.patches_list(package_base, []).get(package_base, [])
|
||||||
|
|
||||||
def patches_insert(self, package_base: str, patch: str) -> None:
|
def patches_insert(self, package_base: str, patch: PkgbuildPatch) -> None:
|
||||||
"""
|
"""
|
||||||
insert or update patch in database
|
insert or update patch in database
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
package_base(str): package base to insert
|
package_base(str): package base to insert
|
||||||
patch(str): patch content
|
patch(PkgbuildPatch): patch content
|
||||||
"""
|
"""
|
||||||
def run(connection: Connection) -> None:
|
def run(connection: Connection) -> None:
|
||||||
connection.execute(
|
connection.execute(
|
||||||
"""
|
"""
|
||||||
insert into patches
|
insert into patches
|
||||||
(package_base, patch)
|
(package_base, variable, patch)
|
||||||
values
|
values
|
||||||
(:package_base, :patch)
|
(:package_base, :variable, :patch)
|
||||||
on conflict (package_base) do update set
|
on conflict (package_base, coalesce(variable, '')) do update set
|
||||||
patch = :patch
|
patch = :patch
|
||||||
""",
|
""",
|
||||||
{"package_base": package_base, "patch": patch})
|
{"package_base": package_base, "variable": patch.key, "patch": patch.value})
|
||||||
|
|
||||||
return self.with_connection(run, commit=True)
|
return self.with_connection(run, commit=True)
|
||||||
|
|
||||||
def patches_list(self, package_base: Optional[str]) -> Dict[str, str]:
|
def patches_list(self, package_base: Optional[str], variables: List[str]) -> Dict[str, List[PkgbuildPatch]]:
|
||||||
"""
|
"""
|
||||||
extract all patches
|
extract all patches
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
package_base(Optional[str]): optional filter by package base
|
package_base(Optional[str]): optional filter by package base
|
||||||
|
variables(List[str]): extract patches only for specified PKGBUILD variables
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Dict[str, str]: map of package base to patch content
|
Dict[str, List[PkgbuildPatch]]: map of package base to patch content
|
||||||
"""
|
"""
|
||||||
def run(connection: Connection) -> Dict[str, str]:
|
def run(connection: Connection) -> List[Tuple[str, PkgbuildPatch]]:
|
||||||
return {
|
return [
|
||||||
cursor["package_base"]: cursor["patch"]
|
(cursor["package_base"], PkgbuildPatch(cursor["variable"], cursor["patch"]))
|
||||||
for cursor in connection.execute(
|
for cursor in connection.execute(
|
||||||
"""select * from patches where :package_base is null or package_base = :package_base""",
|
"""select * from patches where :package_base is null or package_base = :package_base""",
|
||||||
{"package_base": package_base})
|
{"package_base": package_base})
|
||||||
}
|
]
|
||||||
|
|
||||||
return self.with_connection(run)
|
# we could use itertools & operator but why?
|
||||||
|
patches: Dict[str, List[PkgbuildPatch]] = defaultdict(list)
|
||||||
|
for package, patch in self.with_connection(run):
|
||||||
|
if variables and patch.key not in variables:
|
||||||
|
continue
|
||||||
|
patches[package].append(patch)
|
||||||
|
return dict(patches)
|
||||||
|
|
||||||
def patches_remove(self, package_base: str) -> None:
|
def patches_remove(self, package_base: str, variables: List[str]) -> None:
|
||||||
"""
|
"""
|
||||||
remove patch set
|
remove patch set
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
package_base(str): package base to clear patches
|
package_base(str): package base to clear patches
|
||||||
|
variables(List[str]): remove patches only for specified PKGBUILD variables
|
||||||
"""
|
"""
|
||||||
|
def run_many(connection: Connection) -> None:
|
||||||
|
connection.executemany(
|
||||||
|
"""delete from patches where package_base = :package_base and variable = :variable""",
|
||||||
|
[{"package_base": package_base, "variable": variable} for variable in variables])
|
||||||
|
|
||||||
def run(connection: Connection) -> None:
|
def run(connection: Connection) -> None:
|
||||||
connection.execute(
|
connection.execute(
|
||||||
"""delete from patches where package_base = :package_base""",
|
"""delete from patches where package_base = :package_base""",
|
||||||
{"package_base": package_base})
|
{"package_base": package_base})
|
||||||
|
|
||||||
|
if variables:
|
||||||
|
return self.with_connection(run_many, commit=True)
|
||||||
return self.with_connection(run, commit=True)
|
return self.with_connection(run, commit=True)
|
||||||
|
@ -24,6 +24,7 @@ from ahriman.core.formatters.aur_printer import AurPrinter
|
|||||||
from ahriman.core.formatters.build_printer import BuildPrinter
|
from ahriman.core.formatters.build_printer import BuildPrinter
|
||||||
from ahriman.core.formatters.configuration_printer import ConfigurationPrinter
|
from ahriman.core.formatters.configuration_printer import ConfigurationPrinter
|
||||||
from ahriman.core.formatters.package_printer import PackagePrinter
|
from ahriman.core.formatters.package_printer import PackagePrinter
|
||||||
|
from ahriman.core.formatters.patch_printer import PatchPrinter
|
||||||
from ahriman.core.formatters.status_printer import StatusPrinter
|
from ahriman.core.formatters.status_printer import StatusPrinter
|
||||||
from ahriman.core.formatters.update_printer import UpdatePrinter
|
from ahriman.core.formatters.update_printer import UpdatePrinter
|
||||||
from ahriman.core.formatters.user_printer import UserPrinter
|
from ahriman.core.formatters.user_printer import UserPrinter
|
||||||
|
56
src/ahriman/core/formatters/patch_printer.py
Normal file
56
src/ahriman/core/formatters/patch_printer.py
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
#
|
||||||
|
# Copyright (c) 2021-2022 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 typing import List
|
||||||
|
|
||||||
|
from ahriman.core.formatters import StringPrinter
|
||||||
|
from ahriman.models.pkgbuild_patch import PkgbuildPatch
|
||||||
|
from ahriman.models.property import Property
|
||||||
|
|
||||||
|
|
||||||
|
class PatchPrinter(StringPrinter):
|
||||||
|
"""
|
||||||
|
print content of the PKGBUILD patch
|
||||||
|
|
||||||
|
Attributes:
|
||||||
|
patches(List[PkgbuildPatch]): PKGBUILD patch object
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, package_base: str, patches: List[PkgbuildPatch]) -> None:
|
||||||
|
"""
|
||||||
|
default constructor
|
||||||
|
|
||||||
|
Args:
|
||||||
|
package_base(str): package base
|
||||||
|
patches(List[PkgbuildPatch]): PKGBUILD patch object
|
||||||
|
"""
|
||||||
|
StringPrinter.__init__(self, package_base)
|
||||||
|
self.patches = patches
|
||||||
|
|
||||||
|
def properties(self) -> List[Property]:
|
||||||
|
"""
|
||||||
|
convert content into printable data
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
List[Property]: list of content properties
|
||||||
|
"""
|
||||||
|
return [
|
||||||
|
Property(patch.key or "Full source diff", patch.value, is_required=True)
|
||||||
|
for patch in self.patches
|
||||||
|
]
|
@ -109,7 +109,7 @@ class Executor(Cleaner):
|
|||||||
try:
|
try:
|
||||||
self.paths.tree_clear(package_base) # remove all internal files
|
self.paths.tree_clear(package_base) # remove all internal files
|
||||||
self.database.build_queue_clear(package_base)
|
self.database.build_queue_clear(package_base)
|
||||||
self.database.patches_remove(package_base)
|
self.database.patches_remove(package_base, [])
|
||||||
self.reporter.remove(package_base) # we only update status page in case of base removal
|
self.reporter.remove(package_base) # we only update status page in case of base removal
|
||||||
except Exception:
|
except Exception:
|
||||||
self.logger.exception("could not remove base %s", package_base)
|
self.logger.exception("could not remove base %s", package_base)
|
||||||
|
@ -305,7 +305,7 @@ class Package(LazyLogging):
|
|||||||
|
|
||||||
from ahriman.core.build_tools.sources import Sources
|
from ahriman.core.build_tools.sources import Sources
|
||||||
|
|
||||||
Sources.load(paths.cache_for(self.base), self, None, paths)
|
Sources.load(paths.cache_for(self.base), self, [], paths)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# update pkgver first
|
# update pkgver first
|
||||||
|
@ -21,7 +21,7 @@ import shlex
|
|||||||
|
|
||||||
from dataclasses import dataclass, field
|
from dataclasses import dataclass, field
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import List, Union
|
from typing import List, Optional, Union
|
||||||
|
|
||||||
|
|
||||||
@dataclass(frozen=True)
|
@dataclass(frozen=True)
|
||||||
@ -30,16 +30,23 @@ class PkgbuildPatch:
|
|||||||
wrapper for patching PKBGUILDs
|
wrapper for patching PKBGUILDs
|
||||||
|
|
||||||
Attributes:
|
Attributes:
|
||||||
key(str): name of the property in PKGBUILD, e.g. version, url etc
|
key(Optional[str]): name of the property in PKGBUILD, e.g. version, url etc. If not set, patch will be
|
||||||
|
considered as full PKGBUILD diffs
|
||||||
value(Union[str, List[str]]): value of the stored PKGBUILD property. It must be either string or list of string
|
value(Union[str, List[str]]): value of the stored PKGBUILD property. It must be either string or list of string
|
||||||
values
|
values
|
||||||
unsafe(bool): if set, value will be not quoted, might break PKGBUILD
|
unsafe(bool): if set, value will be not quoted, might break PKGBUILD
|
||||||
"""
|
"""
|
||||||
|
|
||||||
key: str
|
key: Optional[str]
|
||||||
value: Union[str, List[str]]
|
value: Union[str, List[str]]
|
||||||
unsafe: bool = field(default=False, kw_only=True)
|
unsafe: bool = field(default=False, kw_only=True)
|
||||||
|
|
||||||
|
def __post_init__(self) -> None:
|
||||||
|
"""
|
||||||
|
remove empty key
|
||||||
|
"""
|
||||||
|
object.__setattr__(self, "key", self.key or None)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def is_function(self) -> bool:
|
def is_function(self) -> bool:
|
||||||
"""
|
"""
|
||||||
@ -48,7 +55,17 @@ class PkgbuildPatch:
|
|||||||
Returns:
|
Returns:
|
||||||
bool: True in case if key ends with parentheses and False otherwise
|
bool: True in case if key ends with parentheses and False otherwise
|
||||||
"""
|
"""
|
||||||
return self.key.endswith("()")
|
return self.key is not None and self.key.endswith("()")
|
||||||
|
|
||||||
|
@property
|
||||||
|
def is_plain_diff(self) -> bool:
|
||||||
|
"""
|
||||||
|
check if patch is full diff one or just single-variable patch
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
bool: True in case key set and False otherwise
|
||||||
|
"""
|
||||||
|
return self.key is None
|
||||||
|
|
||||||
def quote(self, value: str) -> str:
|
def quote(self, value: str) -> str:
|
||||||
"""
|
"""
|
||||||
@ -74,6 +91,8 @@ class PkgbuildPatch:
|
|||||||
if isinstance(self.value, list): # list like
|
if isinstance(self.value, list): # list like
|
||||||
value = " ".join(map(self.quote, self.value))
|
value = " ".join(map(self.quote, self.value))
|
||||||
return f"""{self.key}=({value})"""
|
return f"""{self.key}=({value})"""
|
||||||
|
if self.is_plain_diff: # no additional logic for plain diffs
|
||||||
|
return self.value
|
||||||
# we suppose that function values are only supported in string-like values
|
# we suppose that function values are only supported in string-like values
|
||||||
if self.is_function:
|
if self.is_function:
|
||||||
return f"{self.key} {self.value}" # no quoting enabled here
|
return f"{self.key} {self.value}" # no quoting enabled here
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import argparse
|
import argparse
|
||||||
import pytest
|
import pytest
|
||||||
|
import sys
|
||||||
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from pytest_mock import MockerFixture
|
from pytest_mock import MockerFixture
|
||||||
@ -9,6 +10,7 @@ from ahriman.application.handlers import Patch
|
|||||||
from ahriman.core.configuration import Configuration
|
from ahriman.core.configuration import Configuration
|
||||||
from ahriman.models.action import Action
|
from ahriman.models.action import Action
|
||||||
from ahriman.models.package import Package
|
from ahriman.models.package import Package
|
||||||
|
from ahriman.models.pkgbuild_patch import PkgbuildPatch
|
||||||
|
|
||||||
|
|
||||||
def _default_args(args: argparse.Namespace) -> argparse.Namespace:
|
def _default_args(args: argparse.Namespace) -> argparse.Namespace:
|
||||||
@ -25,6 +27,7 @@ def _default_args(args: argparse.Namespace) -> argparse.Namespace:
|
|||||||
args.exit_code = False
|
args.exit_code = False
|
||||||
args.remove = False
|
args.remove = False
|
||||||
args.track = ["*.diff", "*.patch"]
|
args.track = ["*.diff", "*.patch"]
|
||||||
|
args.variable = None
|
||||||
return args
|
return args
|
||||||
|
|
||||||
|
|
||||||
@ -35,12 +38,31 @@ def test_run(args: argparse.Namespace, configuration: Configuration, mocker: Moc
|
|||||||
args = _default_args(args)
|
args = _default_args(args)
|
||||||
args.action = Action.Update
|
args.action = Action.Update
|
||||||
mocker.patch("ahriman.models.repository_paths.RepositoryPaths.tree_create")
|
mocker.patch("ahriman.models.repository_paths.RepositoryPaths.tree_create")
|
||||||
|
patch_mock = mocker.patch("ahriman.application.handlers.Patch.patch_create_from_diff",
|
||||||
|
return_value=(args.package, PkgbuildPatch(None, "patch")))
|
||||||
application_mock = mocker.patch("ahriman.application.handlers.Patch.patch_set_create")
|
application_mock = mocker.patch("ahriman.application.handlers.Patch.patch_set_create")
|
||||||
on_start_mock = mocker.patch("ahriman.application.application.Application.on_start")
|
|
||||||
|
|
||||||
Patch.run(args, "x86_64", configuration, True, False)
|
Patch.run(args, "x86_64", configuration, True, False)
|
||||||
application_mock.assert_called_once_with(pytest.helpers.anyvar(int), Path(args.package), args.track)
|
patch_mock.assert_called_once_with(args.package, args.track)
|
||||||
on_start_mock.assert_called_once_with()
|
application_mock.assert_called_once_with(pytest.helpers.anyvar(int), args.package, PkgbuildPatch(None, "patch"))
|
||||||
|
|
||||||
|
|
||||||
|
def test_run_function(args: argparse.Namespace, configuration: Configuration, mocker: MockerFixture) -> None:
|
||||||
|
"""
|
||||||
|
must run command with patch function flag
|
||||||
|
"""
|
||||||
|
args = _default_args(args)
|
||||||
|
args.action = Action.Update
|
||||||
|
args.patch = "patch"
|
||||||
|
args.variable = "version"
|
||||||
|
patch = PkgbuildPatch(args.variable, args.patch)
|
||||||
|
mocker.patch("ahriman.models.repository_paths.RepositoryPaths.tree_create")
|
||||||
|
patch_mock = mocker.patch("ahriman.application.handlers.Patch.patch_create_from_function", return_value=patch)
|
||||||
|
application_mock = mocker.patch("ahriman.application.handlers.Patch.patch_set_create")
|
||||||
|
|
||||||
|
Patch.run(args, "x86_64", configuration, True, False)
|
||||||
|
patch_mock.assert_called_once_with(args.variable, args.patch)
|
||||||
|
application_mock.assert_called_once_with(pytest.helpers.anyvar(int), args.package, patch)
|
||||||
|
|
||||||
|
|
||||||
def test_run_list(args: argparse.Namespace, configuration: Configuration, mocker: MockerFixture) -> None:
|
def test_run_list(args: argparse.Namespace, configuration: Configuration, mocker: MockerFixture) -> None:
|
||||||
@ -49,11 +71,12 @@ def test_run_list(args: argparse.Namespace, configuration: Configuration, mocker
|
|||||||
"""
|
"""
|
||||||
args = _default_args(args)
|
args = _default_args(args)
|
||||||
args.action = Action.List
|
args.action = Action.List
|
||||||
|
args.variable = ["version"]
|
||||||
mocker.patch("ahriman.models.repository_paths.RepositoryPaths.tree_create")
|
mocker.patch("ahriman.models.repository_paths.RepositoryPaths.tree_create")
|
||||||
application_mock = mocker.patch("ahriman.application.handlers.Patch.patch_set_list")
|
application_mock = mocker.patch("ahriman.application.handlers.Patch.patch_set_list")
|
||||||
|
|
||||||
Patch.run(args, "x86_64", configuration, True, False)
|
Patch.run(args, "x86_64", configuration, True, False)
|
||||||
application_mock.assert_called_once_with(pytest.helpers.anyvar(int), args.package, False)
|
application_mock.assert_called_once_with(pytest.helpers.anyvar(int), args.package, ["version"], False)
|
||||||
|
|
||||||
|
|
||||||
def test_run_remove(args: argparse.Namespace, configuration: Configuration, mocker: MockerFixture) -> None:
|
def test_run_remove(args: argparse.Namespace, configuration: Configuration, mocker: MockerFixture) -> None:
|
||||||
@ -62,24 +85,71 @@ def test_run_remove(args: argparse.Namespace, configuration: Configuration, mock
|
|||||||
"""
|
"""
|
||||||
args = _default_args(args)
|
args = _default_args(args)
|
||||||
args.action = Action.Remove
|
args.action = Action.Remove
|
||||||
|
args.variable = ["version"]
|
||||||
mocker.patch("ahriman.models.repository_paths.RepositoryPaths.tree_create")
|
mocker.patch("ahriman.models.repository_paths.RepositoryPaths.tree_create")
|
||||||
application_mock = mocker.patch("ahriman.application.handlers.Patch.patch_set_remove")
|
application_mock = mocker.patch("ahriman.application.handlers.Patch.patch_set_remove")
|
||||||
|
|
||||||
Patch.run(args, "x86_64", configuration, True, False)
|
Patch.run(args, "x86_64", configuration, True, False)
|
||||||
application_mock.assert_called_once_with(pytest.helpers.anyvar(int), args.package)
|
application_mock.assert_called_once_with(pytest.helpers.anyvar(int), args.package, ["version"])
|
||||||
|
|
||||||
|
|
||||||
|
def test_patch_create_from_diff(package_ahriman: Package, mocker: MockerFixture) -> None:
|
||||||
|
"""
|
||||||
|
must create patch from directory tree diff
|
||||||
|
"""
|
||||||
|
patch = PkgbuildPatch(None, "patch")
|
||||||
|
path = Path("local")
|
||||||
|
mocker.patch("pathlib.Path.mkdir")
|
||||||
|
package_mock = mocker.patch("ahriman.models.package.Package.from_build", return_value=package_ahriman)
|
||||||
|
sources_mock = mocker.patch("ahriman.core.build_tools.sources.Sources.patch_create", return_value=patch.value)
|
||||||
|
|
||||||
|
assert Patch.patch_create_from_diff(path, ["*.diff"]) == (package_ahriman.base, patch)
|
||||||
|
package_mock.assert_called_once_with(path)
|
||||||
|
sources_mock.assert_called_once_with(path, "*.diff")
|
||||||
|
|
||||||
|
|
||||||
|
def test_patch_create_from_function(mocker: MockerFixture) -> None:
|
||||||
|
"""
|
||||||
|
must create function patch from file
|
||||||
|
"""
|
||||||
|
path = Path("local")
|
||||||
|
patch = PkgbuildPatch("version", "patch")
|
||||||
|
read_mock = mocker.patch("pathlib.Path.read_text", return_value=patch.value)
|
||||||
|
|
||||||
|
assert Patch.patch_create_from_function(patch.key, path) == patch
|
||||||
|
read_mock.assert_called_once_with(encoding="utf8")
|
||||||
|
|
||||||
|
|
||||||
|
def test_patch_create_from_function_stdin(mocker: MockerFixture) -> None:
|
||||||
|
"""
|
||||||
|
must create function patch from stdin
|
||||||
|
"""
|
||||||
|
patch = PkgbuildPatch("version", "This is a patch")
|
||||||
|
mocker.patch.object(sys, "stdin", patch.value.splitlines())
|
||||||
|
assert Patch.patch_create_from_function(patch.key, None) == patch
|
||||||
|
|
||||||
|
|
||||||
|
def test_patch_create_from_function_strip(mocker: MockerFixture) -> None:
|
||||||
|
"""
|
||||||
|
must remove spaces at the beginning and at the end of the line
|
||||||
|
"""
|
||||||
|
patch = PkgbuildPatch("version", "This is a patch")
|
||||||
|
mocker.patch.object(sys, "stdin", ["\n"] + patch.value.splitlines() + ["\n"])
|
||||||
|
assert Patch.patch_create_from_function(patch.key, None) == patch
|
||||||
|
|
||||||
|
|
||||||
def test_patch_set_list(application: Application, mocker: MockerFixture) -> None:
|
def test_patch_set_list(application: Application, mocker: MockerFixture) -> None:
|
||||||
"""
|
"""
|
||||||
must list available patches for the command
|
must list available patches for the command
|
||||||
"""
|
"""
|
||||||
get_mock = mocker.patch("ahriman.core.database.SQLite.patches_list", return_value={"ahriman": "patch"})
|
get_mock = mocker.patch("ahriman.core.database.SQLite.patches_list",
|
||||||
|
return_value={"ahriman": PkgbuildPatch(None, "patch")})
|
||||||
print_mock = mocker.patch("ahriman.core.formatters.Printer.print")
|
print_mock = mocker.patch("ahriman.core.formatters.Printer.print")
|
||||||
check_mock = mocker.patch("ahriman.application.handlers.Handler.check_if_empty")
|
check_mock = mocker.patch("ahriman.application.handlers.Handler.check_if_empty")
|
||||||
|
|
||||||
Patch.patch_set_list(application, "ahriman", False)
|
Patch.patch_set_list(application, "ahriman", ["version"], False)
|
||||||
get_mock.assert_called_once_with("ahriman")
|
get_mock.assert_called_once_with("ahriman", ["version"])
|
||||||
print_mock.assert_called_once_with(verbose=True)
|
print_mock.assert_called_once_with(verbose=True, separator=" = ")
|
||||||
check_mock.assert_called_once_with(False, False)
|
check_mock.assert_called_once_with(False, False)
|
||||||
|
|
||||||
|
|
||||||
@ -90,7 +160,7 @@ def test_patch_set_list_empty_exception(application: Application, mocker: Mocker
|
|||||||
mocker.patch("ahriman.core.database.SQLite.patches_list", return_value={})
|
mocker.patch("ahriman.core.database.SQLite.patches_list", return_value={})
|
||||||
check_mock = mocker.patch("ahriman.application.handlers.Handler.check_if_empty")
|
check_mock = mocker.patch("ahriman.application.handlers.Handler.check_if_empty")
|
||||||
|
|
||||||
Patch.patch_set_list(application, "ahriman", True)
|
Patch.patch_set_list(application, "ahriman", [], True)
|
||||||
check_mock.assert_called_once_with(True, True)
|
check_mock.assert_called_once_with(True, True)
|
||||||
|
|
||||||
|
|
||||||
@ -98,13 +168,9 @@ def test_patch_set_create(application: Application, package_ahriman: Package, mo
|
|||||||
"""
|
"""
|
||||||
must create patch set for the package
|
must create patch set for the package
|
||||||
"""
|
"""
|
||||||
mocker.patch("pathlib.Path.mkdir")
|
|
||||||
mocker.patch("ahriman.models.package.Package.from_build", return_value=package_ahriman)
|
|
||||||
mocker.patch("ahriman.core.build_tools.sources.Sources.patch_create", return_value="patch")
|
|
||||||
create_mock = mocker.patch("ahriman.core.database.SQLite.patches_insert")
|
create_mock = mocker.patch("ahriman.core.database.SQLite.patches_insert")
|
||||||
|
Patch.patch_set_create(application, package_ahriman.base, PkgbuildPatch("version", package_ahriman.version))
|
||||||
Patch.patch_set_create(application, Path("path"), ["*.patch"])
|
create_mock.assert_called_once_with(package_ahriman.base, PkgbuildPatch("version", package_ahriman.version))
|
||||||
create_mock.assert_called_once_with(package_ahriman.base, "patch")
|
|
||||||
|
|
||||||
|
|
||||||
def test_patch_set_remove(application: Application, package_ahriman: Package, mocker: MockerFixture) -> None:
|
def test_patch_set_remove(application: Application, package_ahriman: Package, mocker: MockerFixture) -> None:
|
||||||
@ -112,5 +178,5 @@ def test_patch_set_remove(application: Application, package_ahriman: Package, mo
|
|||||||
must remove patch set for the package
|
must remove patch set for the package
|
||||||
"""
|
"""
|
||||||
remove_mock = mocker.patch("ahriman.core.database.SQLite.patches_remove")
|
remove_mock = mocker.patch("ahriman.core.database.SQLite.patches_remove")
|
||||||
Patch.patch_set_remove(application, package_ahriman.base)
|
Patch.patch_set_remove(application, package_ahriman.base, ["version"])
|
||||||
remove_mock.assert_called_once_with(package_ahriman.base)
|
remove_mock.assert_called_once_with(package_ahriman.base, ["version"])
|
||||||
|
@ -197,7 +197,7 @@ def test_subparsers_patch_add(parser: argparse.ArgumentParser) -> None:
|
|||||||
"""
|
"""
|
||||||
patch-add command must imply action, architecture list, lock and no-report
|
patch-add command must imply action, architecture list, lock and no-report
|
||||||
"""
|
"""
|
||||||
args = parser.parse_args(["patch-add", "ahriman"])
|
args = parser.parse_args(["patch-add", "ahriman", "version"])
|
||||||
assert args.action == Action.Update
|
assert args.action == Action.Update
|
||||||
assert args.architecture == [""]
|
assert args.architecture == [""]
|
||||||
assert args.lock is None
|
assert args.lock is None
|
||||||
@ -208,18 +208,10 @@ def test_subparsers_patch_add_architecture(parser: argparse.ArgumentParser) -> N
|
|||||||
"""
|
"""
|
||||||
patch-add command must correctly parse architecture list
|
patch-add command must correctly parse architecture list
|
||||||
"""
|
"""
|
||||||
args = parser.parse_args(["-a", "x86_64", "patch-add", "ahriman"])
|
args = parser.parse_args(["-a", "x86_64", "patch-add", "ahriman", "version"])
|
||||||
assert args.architecture == [""]
|
assert args.architecture == [""]
|
||||||
|
|
||||||
|
|
||||||
def test_subparsers_patch_add_track(parser: argparse.ArgumentParser) -> None:
|
|
||||||
"""
|
|
||||||
patch-add command must correctly parse track files patterns
|
|
||||||
"""
|
|
||||||
args = parser.parse_args(["patch-add", "-t", "*.py", "ahriman"])
|
|
||||||
assert args.track == ["*.diff", "*.patch", "*.py"]
|
|
||||||
|
|
||||||
|
|
||||||
def test_subparsers_patch_list(parser: argparse.ArgumentParser) -> None:
|
def test_subparsers_patch_list(parser: argparse.ArgumentParser) -> None:
|
||||||
"""
|
"""
|
||||||
patch-list command must imply action, architecture list, lock and no-report
|
patch-list command must imply action, architecture list, lock and no-report
|
||||||
@ -258,6 +250,42 @@ def test_subparsers_patch_remove_architecture(parser: argparse.ArgumentParser) -
|
|||||||
assert args.architecture == [""]
|
assert args.architecture == [""]
|
||||||
|
|
||||||
|
|
||||||
|
def test_subparsers_patch_set_add(parser: argparse.ArgumentParser) -> None:
|
||||||
|
"""
|
||||||
|
patch-set-add command must imply action, architecture list, lock, no-report and variable
|
||||||
|
"""
|
||||||
|
args = parser.parse_args(["patch-set-add", "ahriman"])
|
||||||
|
assert args.action == Action.Update
|
||||||
|
assert args.architecture == [""]
|
||||||
|
assert args.lock is None
|
||||||
|
assert args.no_report
|
||||||
|
assert args.variable is None
|
||||||
|
|
||||||
|
|
||||||
|
def test_subparsers_patch_set_add_architecture(parser: argparse.ArgumentParser) -> None:
|
||||||
|
"""
|
||||||
|
patch-set-add command must correctly parse architecture list
|
||||||
|
"""
|
||||||
|
args = parser.parse_args(["-a", "x86_64", "patch-set-add", "ahriman"])
|
||||||
|
assert args.architecture == [""]
|
||||||
|
|
||||||
|
|
||||||
|
def test_subparsers_patch_set_add_option_package(parser: argparse.ArgumentParser) -> None:
|
||||||
|
"""
|
||||||
|
patch-set-add command must convert package option to path instance
|
||||||
|
"""
|
||||||
|
args = parser.parse_args(["patch-set-add", "ahriman"])
|
||||||
|
assert isinstance(args.package, Path)
|
||||||
|
|
||||||
|
|
||||||
|
def test_subparsers_patch_set_add_option_track(parser: argparse.ArgumentParser) -> None:
|
||||||
|
"""
|
||||||
|
patch-set-add command must correctly parse track files patterns
|
||||||
|
"""
|
||||||
|
args = parser.parse_args(["patch-set-add", "-t", "*.py", "ahriman"])
|
||||||
|
assert args.track == ["*.diff", "*.patch", "*.py"]
|
||||||
|
|
||||||
|
|
||||||
def test_subparsers_repo_backup(parser: argparse.ArgumentParser) -> None:
|
def test_subparsers_repo_backup(parser: argparse.ArgumentParser) -> None:
|
||||||
"""
|
"""
|
||||||
repo-backup command must imply architecture list, lock, no-report and unsafe
|
repo-backup command must imply architecture list, lock, no-report and unsafe
|
||||||
|
@ -6,6 +6,7 @@ from unittest import mock
|
|||||||
|
|
||||||
from ahriman.core.build_tools.sources import Sources
|
from ahriman.core.build_tools.sources import Sources
|
||||||
from ahriman.models.package import Package
|
from ahriman.models.package import Package
|
||||||
|
from ahriman.models.pkgbuild_patch import PkgbuildPatch
|
||||||
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
|
||||||
|
|
||||||
@ -16,11 +17,9 @@ def test_extend_architectures(mocker: MockerFixture) -> None:
|
|||||||
"""
|
"""
|
||||||
mocker.patch("pathlib.Path.is_file", return_value=True)
|
mocker.patch("pathlib.Path.is_file", return_value=True)
|
||||||
archs_mock = mocker.patch("ahriman.models.package.Package.supported_architectures", return_value={"x86_64"})
|
archs_mock = mocker.patch("ahriman.models.package.Package.supported_architectures", return_value={"x86_64"})
|
||||||
write_mock = mocker.patch("ahriman.models.pkgbuild_patch.PkgbuildPatch.write")
|
|
||||||
|
|
||||||
Sources.extend_architectures(Path("local"), "i686")
|
assert Sources.extend_architectures(Path("local"), "i686") == [PkgbuildPatch("arch", list({"x86_64", "i686"}))]
|
||||||
archs_mock.assert_called_once_with(Path("local"))
|
archs_mock.assert_called_once_with(Path("local"))
|
||||||
write_mock.assert_called_once_with(Path("local") / "PKGBUILD")
|
|
||||||
|
|
||||||
|
|
||||||
def test_extend_architectures_any(mocker: MockerFixture) -> None:
|
def test_extend_architectures_any(mocker: MockerFixture) -> None:
|
||||||
@ -29,21 +28,7 @@ def test_extend_architectures_any(mocker: MockerFixture) -> None:
|
|||||||
"""
|
"""
|
||||||
mocker.patch("pathlib.Path.is_file", return_value=True)
|
mocker.patch("pathlib.Path.is_file", return_value=True)
|
||||||
mocker.patch("ahriman.models.package.Package.supported_architectures", return_value={"any"})
|
mocker.patch("ahriman.models.package.Package.supported_architectures", return_value={"any"})
|
||||||
write_mock = mocker.patch("ahriman.models.pkgbuild_patch.PkgbuildPatch.write")
|
assert Sources.extend_architectures(Path("local"), "i686") == []
|
||||||
|
|
||||||
Sources.extend_architectures(Path("local"), "i686")
|
|
||||||
write_mock.assert_not_called()
|
|
||||||
|
|
||||||
|
|
||||||
def test_extend_architectures_skip(mocker: MockerFixture) -> None:
|
|
||||||
"""
|
|
||||||
must skip extending list of the architectures in case if no PKGBUILD file found
|
|
||||||
"""
|
|
||||||
mocker.patch("pathlib.Path.is_file", return_value=False)
|
|
||||||
write_mock = mocker.patch("ahriman.models.pkgbuild_patch.PkgbuildPatch.write")
|
|
||||||
|
|
||||||
Sources.extend_architectures(Path("local"), "i686")
|
|
||||||
write_mock.assert_not_called()
|
|
||||||
|
|
||||||
|
|
||||||
def test_fetch_empty(remote_source: RemoteSource, mocker: MockerFixture) -> None:
|
def test_fetch_empty(remote_source: RemoteSource, mocker: MockerFixture) -> None:
|
||||||
@ -167,15 +152,16 @@ def test_load(package_ahriman: Package, repository_paths: RepositoryPaths, mocke
|
|||||||
"""
|
"""
|
||||||
must load packages sources correctly
|
must load packages sources correctly
|
||||||
"""
|
"""
|
||||||
mocker.patch("pathlib.Path.is_dir", return_value=False)
|
patch = PkgbuildPatch(None, "patch")
|
||||||
|
path = Path("local")
|
||||||
fetch_mock = mocker.patch("ahriman.core.build_tools.sources.Sources.fetch")
|
fetch_mock = mocker.patch("ahriman.core.build_tools.sources.Sources.fetch")
|
||||||
patch_mock = mocker.patch("ahriman.core.build_tools.sources.Sources.patch_apply")
|
patch_mock = mocker.patch("ahriman.core.build_tools.sources.Sources.patch_apply")
|
||||||
architectures_mock = mocker.patch("ahriman.core.build_tools.sources.Sources.extend_architectures")
|
architectures_mock = mocker.patch("ahriman.core.build_tools.sources.Sources.extend_architectures", return_value=[])
|
||||||
|
|
||||||
Sources.load(Path("local"), package_ahriman, "patch", repository_paths)
|
Sources.load(path, package_ahriman, [patch], repository_paths)
|
||||||
fetch_mock.assert_called_once_with(Path("local"), package_ahriman.remote)
|
fetch_mock.assert_called_once_with(path, package_ahriman.remote)
|
||||||
patch_mock.assert_called_once_with(Path("local"), "patch")
|
patch_mock.assert_called_once_with(path, patch)
|
||||||
architectures_mock.assert_called_once_with(Path("local"), repository_paths.architecture)
|
architectures_mock.assert_called_once_with(path, repository_paths.architecture)
|
||||||
|
|
||||||
|
|
||||||
def test_load_no_patch(package_ahriman: Package, repository_paths: RepositoryPaths, mocker: MockerFixture) -> None:
|
def test_load_no_patch(package_ahriman: Package, repository_paths: RepositoryPaths, mocker: MockerFixture) -> None:
|
||||||
@ -184,9 +170,10 @@ def test_load_no_patch(package_ahriman: Package, repository_paths: RepositoryPat
|
|||||||
"""
|
"""
|
||||||
mocker.patch("pathlib.Path.is_dir", return_value=False)
|
mocker.patch("pathlib.Path.is_dir", return_value=False)
|
||||||
mocker.patch("ahriman.core.build_tools.sources.Sources.fetch")
|
mocker.patch("ahriman.core.build_tools.sources.Sources.fetch")
|
||||||
|
mocker.patch("ahriman.core.build_tools.sources.Sources.extend_architectures", return_value=[])
|
||||||
patch_mock = mocker.patch("ahriman.core.build_tools.sources.Sources.patch_apply")
|
patch_mock = mocker.patch("ahriman.core.build_tools.sources.Sources.patch_apply")
|
||||||
|
|
||||||
Sources.load(Path("local"), package_ahriman, None, repository_paths)
|
Sources.load(Path("local"), package_ahriman, [], repository_paths)
|
||||||
patch_mock.assert_not_called()
|
patch_mock.assert_not_called()
|
||||||
|
|
||||||
|
|
||||||
@ -197,8 +184,9 @@ def test_load_with_cache(package_ahriman: Package, repository_paths: RepositoryP
|
|||||||
mocker.patch("pathlib.Path.is_dir", return_value=True)
|
mocker.patch("pathlib.Path.is_dir", return_value=True)
|
||||||
copytree_mock = mocker.patch("shutil.copytree")
|
copytree_mock = mocker.patch("shutil.copytree")
|
||||||
mocker.patch("ahriman.core.build_tools.sources.Sources.fetch")
|
mocker.patch("ahriman.core.build_tools.sources.Sources.fetch")
|
||||||
|
mocker.patch("ahriman.core.build_tools.sources.Sources.extend_architectures", return_value=[])
|
||||||
|
|
||||||
Sources.load(Path("local"), package_ahriman, None, repository_paths)
|
Sources.load(Path("local"), package_ahriman, [], repository_paths)
|
||||||
copytree_mock.assert_called_once() # we do not check full command here, sorry
|
copytree_mock.assert_called_once() # we do not check full command here, sorry
|
||||||
|
|
||||||
|
|
||||||
@ -331,11 +319,24 @@ def test_patch_apply(sources: Sources, mocker: MockerFixture) -> None:
|
|||||||
"""
|
"""
|
||||||
must apply patches if any
|
must apply patches if any
|
||||||
"""
|
"""
|
||||||
|
patch = PkgbuildPatch(None, "patch")
|
||||||
check_output_mock = mocker.patch("ahriman.core.build_tools.sources.Sources._check_output")
|
check_output_mock = mocker.patch("ahriman.core.build_tools.sources.Sources._check_output")
|
||||||
|
|
||||||
local = Path("local")
|
local = Path("local")
|
||||||
sources.patch_apply(local, "patches")
|
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",
|
"git", "apply", "--ignore-space-change", "--ignore-whitespace",
|
||||||
exception=None, cwd=local, input_data="patches", logger=pytest.helpers.anyvar(int)
|
exception=None, cwd=local, input_data=patch.value, logger=pytest.helpers.anyvar(int)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_patch_apply_function(sources: Sources, mocker: MockerFixture) -> None:
|
||||||
|
"""
|
||||||
|
must apply single-function patches
|
||||||
|
"""
|
||||||
|
patch = PkgbuildPatch("version", "42")
|
||||||
|
local = Path("local")
|
||||||
|
write_mock = mocker.patch("ahriman.models.pkgbuild_patch.PkgbuildPatch.write")
|
||||||
|
|
||||||
|
sources.patch_apply(local, patch)
|
||||||
|
write_mock.assert_called_once_with(local / "PKGBUILD")
|
||||||
|
@ -20,4 +20,4 @@ def test_init(task_ahriman: Task, database: SQLite, mocker: MockerFixture) -> No
|
|||||||
"""
|
"""
|
||||||
load_mock = mocker.patch("ahriman.core.build_tools.sources.Sources.load")
|
load_mock = mocker.patch("ahriman.core.build_tools.sources.Sources.load")
|
||||||
task_ahriman.init(Path("ahriman"), database)
|
task_ahriman.init(Path("ahriman"), database)
|
||||||
load_mock.assert_called_once_with(Path("ahriman"), task_ahriman.package, None, task_ahriman.paths)
|
load_mock.assert_called_once_with(Path("ahriman"), task_ahriman.package, [], task_ahriman.paths)
|
||||||
|
@ -0,0 +1,8 @@
|
|||||||
|
from ahriman.core.database.migrations.m003_patch_variables import steps
|
||||||
|
|
||||||
|
|
||||||
|
def test_migration_package_source() -> None:
|
||||||
|
"""
|
||||||
|
migration must not be empty
|
||||||
|
"""
|
||||||
|
assert steps
|
@ -1,55 +1,96 @@
|
|||||||
from ahriman.core.database import SQLite
|
from ahriman.core.database import SQLite
|
||||||
from ahriman.models.package import Package
|
from ahriman.models.package import Package
|
||||||
|
from ahriman.models.pkgbuild_patch import PkgbuildPatch
|
||||||
|
|
||||||
|
|
||||||
def test_patches_get_insert(database: SQLite, package_ahriman: Package, package_python_schedule: Package) -> None:
|
def test_patches_get_insert(database: SQLite, package_ahriman: Package, package_python_schedule: Package) -> None:
|
||||||
"""
|
"""
|
||||||
must insert patch to database
|
must insert patch to database
|
||||||
"""
|
"""
|
||||||
database.patches_insert(package_ahriman.base, "patch_1")
|
database.patches_insert(package_ahriman.base, PkgbuildPatch(None, "patch_1"))
|
||||||
database.patches_insert(package_python_schedule.base, "patch_2")
|
database.patches_insert(package_ahriman.base, PkgbuildPatch("key", "patch_3"))
|
||||||
assert database.patches_get(package_ahriman.base) == "patch_1"
|
database.patches_insert(package_python_schedule.base, PkgbuildPatch(None, "patch_2"))
|
||||||
assert not database.build_queue_get()
|
assert database.patches_get(package_ahriman.base) == [
|
||||||
|
PkgbuildPatch(None, "patch_1"), PkgbuildPatch("key", "patch_3")
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
def test_patches_list(database: SQLite, package_ahriman: Package, package_python_schedule: Package) -> None:
|
def test_patches_list(database: SQLite, package_ahriman: Package, package_python_schedule: Package) -> None:
|
||||||
"""
|
"""
|
||||||
must list all patches
|
must list all patches
|
||||||
"""
|
"""
|
||||||
database.patches_insert(package_ahriman.base, "patch1")
|
database.patches_insert(package_ahriman.base, PkgbuildPatch(None, "patch1"))
|
||||||
database.patches_insert(package_python_schedule.base, "patch2")
|
database.patches_insert(package_ahriman.base, PkgbuildPatch("key", "patch3"))
|
||||||
assert database.patches_list(None) == {package_ahriman.base: "patch1", package_python_schedule.base: "patch2"}
|
database.patches_insert(package_python_schedule.base, PkgbuildPatch(None, "patch2"))
|
||||||
|
assert database.patches_list(None, []) == {
|
||||||
|
package_ahriman.base: [PkgbuildPatch(None, "patch1"), PkgbuildPatch("key", "patch3")],
|
||||||
|
package_python_schedule.base: [PkgbuildPatch(None, "patch2")],
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
def test_patches_list_filter(database: SQLite, package_ahriman: Package, package_python_schedule: Package) -> None:
|
def test_patches_list_filter(database: SQLite, package_ahriman: Package, package_python_schedule: Package) -> None:
|
||||||
"""
|
"""
|
||||||
must list all patches filtered by package name (same as get)
|
must list all patches filtered by package name (same as get)
|
||||||
"""
|
"""
|
||||||
database.patches_insert(package_ahriman.base, "patch1")
|
database.patches_insert(package_ahriman.base, PkgbuildPatch(None, "patch1"))
|
||||||
database.patches_insert(package_python_schedule.base, "patch2")
|
database.patches_insert(package_python_schedule.base, PkgbuildPatch(None, "patch2"))
|
||||||
|
|
||||||
assert database.patches_list(package_ahriman.base) == {package_ahriman.base: "patch1"}
|
assert database.patches_list(package_ahriman.base, []) == {package_ahriman.base: [PkgbuildPatch(None, "patch1")]}
|
||||||
assert database.patches_list(package_python_schedule.base) == {package_python_schedule.base: "patch2"}
|
assert database.patches_list(package_python_schedule.base, []) == {
|
||||||
|
package_python_schedule.base: [PkgbuildPatch(None, "patch2")],
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def test_patches_list_filter_by_variable(database: SQLite, package_ahriman: Package,
|
||||||
|
package_python_schedule: Package) -> None:
|
||||||
|
"""
|
||||||
|
must list all patches filtered by package name (same as get)
|
||||||
|
"""
|
||||||
|
database.patches_insert(package_ahriman.base, PkgbuildPatch(None, "patch1"))
|
||||||
|
database.patches_insert(package_ahriman.base, PkgbuildPatch("key", "patch2"))
|
||||||
|
database.patches_insert(package_python_schedule.base, PkgbuildPatch(None, "patch3"))
|
||||||
|
|
||||||
|
assert database.patches_list(None, []) == {
|
||||||
|
package_ahriman.base: [PkgbuildPatch(None, "patch1"), PkgbuildPatch("key", "patch2")],
|
||||||
|
package_python_schedule.base: [PkgbuildPatch(None, "patch3")],
|
||||||
|
}
|
||||||
|
assert database.patches_list(None, ["key"]) == {
|
||||||
|
package_ahriman.base: [PkgbuildPatch("key", "patch2")],
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
def test_patches_insert_remove(database: SQLite, package_ahriman: Package, package_python_schedule: Package) -> None:
|
def test_patches_insert_remove(database: SQLite, package_ahriman: Package, package_python_schedule: Package) -> None:
|
||||||
"""
|
"""
|
||||||
must remove patch from database
|
must remove patch from database
|
||||||
"""
|
"""
|
||||||
database.patches_insert(package_ahriman.base, "patch_1")
|
database.patches_insert(package_ahriman.base, PkgbuildPatch(None, "patch1"))
|
||||||
database.patches_insert(package_python_schedule.base, "patch_2")
|
database.patches_insert(package_python_schedule.base, PkgbuildPatch(None, "patch2"))
|
||||||
database.patches_remove(package_ahriman.base)
|
database.patches_remove(package_ahriman.base, [])
|
||||||
|
|
||||||
assert database.patches_get(package_ahriman.base) is None
|
assert database.patches_get(package_ahriman.base) == []
|
||||||
database.patches_insert(package_python_schedule.base, "patch_2")
|
assert database.patches_get(package_python_schedule.base) == [PkgbuildPatch(None, "patch2")]
|
||||||
|
|
||||||
|
|
||||||
|
def test_patches_insert_remove_by_variable(database: SQLite, package_ahriman: Package,
|
||||||
|
package_python_schedule: Package) -> None:
|
||||||
|
"""
|
||||||
|
must remove patch from database by variable
|
||||||
|
"""
|
||||||
|
database.patches_insert(package_ahriman.base, PkgbuildPatch(None, "patch1"))
|
||||||
|
database.patches_insert(package_ahriman.base, PkgbuildPatch("key", "patch3"))
|
||||||
|
database.patches_insert(package_python_schedule.base, PkgbuildPatch(None, "patch2"))
|
||||||
|
database.patches_remove(package_ahriman.base, ["key"])
|
||||||
|
|
||||||
|
assert database.patches_get(package_ahriman.base) == [PkgbuildPatch(None, "patch1")]
|
||||||
|
assert database.patches_get(package_python_schedule.base) == [PkgbuildPatch(None, "patch2")]
|
||||||
|
|
||||||
|
|
||||||
def test_patches_insert_insert(database: SQLite, package_ahriman: Package) -> None:
|
def test_patches_insert_insert(database: SQLite, package_ahriman: Package) -> None:
|
||||||
"""
|
"""
|
||||||
must update patch in database
|
must update patch in database
|
||||||
"""
|
"""
|
||||||
database.patches_insert(package_ahriman.base, "patch_1")
|
database.patches_insert(package_ahriman.base, PkgbuildPatch(None, "patch1"))
|
||||||
assert database.patches_get(package_ahriman.base) == "patch_1"
|
assert database.patches_get(package_ahriman.base) == [PkgbuildPatch(None, "patch1")]
|
||||||
|
|
||||||
database.patches_insert(package_ahriman.base, "patch_2")
|
database.patches_insert(package_ahriman.base, PkgbuildPatch(None, "patch2"))
|
||||||
assert database.patches_get(package_ahriman.base) == "patch_2"
|
assert database.patches_get(package_ahriman.base) == [PkgbuildPatch(None, "patch2")]
|
||||||
|
@ -1,10 +1,11 @@
|
|||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from ahriman.core.formatters import AurPrinter, ConfigurationPrinter, PackagePrinter, StatusPrinter, StringPrinter, \
|
from ahriman.core.formatters import AurPrinter, ConfigurationPrinter, PackagePrinter, PatchPrinter, StatusPrinter, \
|
||||||
UpdatePrinter, UserPrinter, VersionPrinter
|
StringPrinter, UpdatePrinter, UserPrinter, VersionPrinter
|
||||||
from ahriman.models.aur_package import AURPackage
|
from ahriman.models.aur_package import AURPackage
|
||||||
from ahriman.models.build_status import BuildStatus
|
from ahriman.models.build_status import BuildStatus
|
||||||
from ahriman.models.package import Package
|
from ahriman.models.package import Package
|
||||||
|
from ahriman.models.pkgbuild_patch import PkgbuildPatch
|
||||||
from ahriman.models.user import User
|
from ahriman.models.user import User
|
||||||
|
|
||||||
|
|
||||||
@ -47,6 +48,20 @@ def package_ahriman_printer(package_ahriman: Package) -> PackagePrinter:
|
|||||||
return PackagePrinter(package_ahriman, BuildStatus())
|
return PackagePrinter(package_ahriman, BuildStatus())
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def patch_printer(package_ahriman: Package) -> PatchPrinter:
|
||||||
|
"""
|
||||||
|
fixture for patch printer
|
||||||
|
|
||||||
|
Args:
|
||||||
|
package_ahriman(Package): package fixture
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
PatchPrinter: patch printer test instance
|
||||||
|
"""
|
||||||
|
return PatchPrinter(package_ahriman.base, [PkgbuildPatch("key", "value")])
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def status_printer() -> StatusPrinter:
|
def status_printer() -> StatusPrinter:
|
||||||
"""
|
"""
|
||||||
|
22
tests/ahriman/core/formatters/test_patch_printer.py
Normal file
22
tests/ahriman/core/formatters/test_patch_printer.py
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
from ahriman.core.formatters import PatchPrinter
|
||||||
|
|
||||||
|
|
||||||
|
def test_properties(patch_printer: PatchPrinter) -> None:
|
||||||
|
"""
|
||||||
|
must return non empty properties list
|
||||||
|
"""
|
||||||
|
assert patch_printer.properties()
|
||||||
|
|
||||||
|
|
||||||
|
def test_properties_required(patch_printer: PatchPrinter) -> None:
|
||||||
|
"""
|
||||||
|
must return all properties as required
|
||||||
|
"""
|
||||||
|
assert all(prop.is_required for prop in patch_printer.properties())
|
||||||
|
|
||||||
|
|
||||||
|
def test_title(patch_printer: PatchPrinter) -> None:
|
||||||
|
"""
|
||||||
|
must return non empty title
|
||||||
|
"""
|
||||||
|
assert patch_printer.title() == "ahriman"
|
@ -72,7 +72,7 @@ def test_process_remove_base(executor: Executor, package_ahriman: Package, mocke
|
|||||||
# must update status and remove package files
|
# must update status and remove package files
|
||||||
tree_clear_mock.assert_called_once_with(package_ahriman.base)
|
tree_clear_mock.assert_called_once_with(package_ahriman.base)
|
||||||
build_queue_mock.assert_called_once_with(package_ahriman.base)
|
build_queue_mock.assert_called_once_with(package_ahriman.base)
|
||||||
patches_mock.assert_called_once_with(package_ahriman.base)
|
patches_mock.assert_called_once_with(package_ahriman.base, [])
|
||||||
status_client_mock.assert_called_once_with(package_ahriman.base)
|
status_client_mock.assert_called_once_with(package_ahriman.base)
|
||||||
|
|
||||||
|
|
||||||
|
@ -49,8 +49,7 @@ def test_leaf_load(package_ahriman: Package, repository_paths: RepositoryPaths,
|
|||||||
leaf = Leaf.load(package_ahriman, repository_paths, database)
|
leaf = Leaf.load(package_ahriman, repository_paths, database)
|
||||||
assert leaf.package == package_ahriman
|
assert leaf.package == package_ahriman
|
||||||
assert leaf.dependencies == {"ahriman-dependency"}
|
assert leaf.dependencies == {"ahriman-dependency"}
|
||||||
load_mock.assert_called_once_with(
|
load_mock.assert_called_once_with(pytest.helpers.anyvar(int), package_ahriman, [], repository_paths)
|
||||||
pytest.helpers.anyvar(int), package_ahriman, None, repository_paths)
|
|
||||||
dependencies_mock.assert_called_once_with(pytest.helpers.anyvar(int))
|
dependencies_mock.assert_called_once_with(pytest.helpers.anyvar(int))
|
||||||
|
|
||||||
|
|
||||||
|
@ -5,6 +5,15 @@ from unittest.mock import MagicMock, call
|
|||||||
from ahriman.models.pkgbuild_patch import PkgbuildPatch
|
from ahriman.models.pkgbuild_patch import PkgbuildPatch
|
||||||
|
|
||||||
|
|
||||||
|
def test_post_init() -> None:
|
||||||
|
"""
|
||||||
|
must remove empty keys
|
||||||
|
"""
|
||||||
|
assert PkgbuildPatch("", "value").key is None
|
||||||
|
assert PkgbuildPatch(None, "value").key is None
|
||||||
|
assert PkgbuildPatch("key", "value").key == "key"
|
||||||
|
|
||||||
|
|
||||||
def test_is_function() -> None:
|
def test_is_function() -> None:
|
||||||
"""
|
"""
|
||||||
must correctly define key as function
|
must correctly define key as function
|
||||||
@ -13,6 +22,14 @@ def test_is_function() -> None:
|
|||||||
assert PkgbuildPatch("key()", "value").is_function
|
assert PkgbuildPatch("key()", "value").is_function
|
||||||
|
|
||||||
|
|
||||||
|
def test_is_plain_diff() -> None:
|
||||||
|
"""
|
||||||
|
must correctly define key as function
|
||||||
|
"""
|
||||||
|
assert not PkgbuildPatch("key", "value").is_plain_diff
|
||||||
|
assert PkgbuildPatch(None, "value").is_plain_diff
|
||||||
|
|
||||||
|
|
||||||
def test_quote() -> None:
|
def test_quote() -> None:
|
||||||
"""
|
"""
|
||||||
must quote strings if unsafe flag is not set
|
must quote strings if unsafe flag is not set
|
||||||
@ -32,6 +49,13 @@ def test_serialize() -> None:
|
|||||||
assert PkgbuildPatch("key", "4'2", unsafe=True).serialize() == "key=4'2"
|
assert PkgbuildPatch("key", "4'2", unsafe=True).serialize() == "key=4'2"
|
||||||
|
|
||||||
|
|
||||||
|
def test_serialize_plain_diff() -> None:
|
||||||
|
"""
|
||||||
|
must correctly serialize function values
|
||||||
|
"""
|
||||||
|
assert PkgbuildPatch(None, "{ value }").serialize() == "{ value }"
|
||||||
|
|
||||||
|
|
||||||
def test_serialize_function() -> None:
|
def test_serialize_function() -> None:
|
||||||
"""
|
"""
|
||||||
must correctly serialize function values
|
must correctly serialize function values
|
||||||
|
Loading…
Reference in New Issue
Block a user