mirror of
https://github.com/arcan1s/ahriman.git
synced 2025-06-27 22:31:43 +00:00
Compare commits
7 Commits
Author | SHA1 | Date | |
---|---|---|---|
733c014229 | |||
783c16b2ed | |||
2536b8dc1f | |||
e200ac9776 | |||
6946745153 | |||
6de75377c3 | |||
a734b86e66 |
2
.github/workflows/docker-image.yml
vendored
2
.github/workflows/docker-image.yml
vendored
@ -3,6 +3,8 @@ name: docker image
|
||||
on:
|
||||
push:
|
||||
branches: [ master ]
|
||||
tags:
|
||||
- '*'
|
||||
|
||||
jobs:
|
||||
docker-image:
|
||||
|
2
.github/workflows/release.yml
vendored
2
.github/workflows/release.yml
vendored
@ -3,7 +3,7 @@ name: release
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- '*.*.*'
|
||||
- '*'
|
||||
|
||||
jobs:
|
||||
make-release:
|
||||
|
File diff suppressed because it is too large
Load Diff
Before Width: | Height: | Size: 503 KiB After Width: | Height: | Size: 508 KiB |
@ -3,7 +3,7 @@
|
||||
ahriman
|
||||
.SH SYNOPSIS
|
||||
.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-check,check,repo-clean,clean,repo-config,config,repo-rebuild,rebuild,repo-remove-unknown,remove-unknown,repo-report,report,repo-setup,init,repo-init,setup,repo-sign,sign,repo-status-update,repo-sync,sync,repo-update,update,user-add,user-list,user-remove,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,repo-check,check,repo-clean,clean,repo-config,config,repo-rebuild,rebuild,repo-remove-unknown,remove-unknown,repo-report,report,repo-restore,restore,repo-setup,init,repo-init,setup,repo-sign,sign,repo-status-update,repo-sync,sync,repo-update,update,user-add,user-list,user-remove,web} ...
|
||||
.SH DESCRIPTION
|
||||
ArcH Linux ReposItory MANager
|
||||
.SH OPTIONS
|
||||
@ -97,6 +97,9 @@ remove unknown packages
|
||||
\fBahriman\fR \fI\,repo-report\/\fR
|
||||
generate report
|
||||
.TP
|
||||
\fBahriman\fR \fI\,repo-restore\/\fR
|
||||
restore repository
|
||||
.TP
|
||||
\fBahriman\fR \fI\,repo-setup\/\fR
|
||||
initial service configuration
|
||||
.TP
|
||||
@ -207,7 +210,7 @@ key server for key import
|
||||
|
||||
.SH OPTIONS 'ahriman package-add'
|
||||
usage: ahriman package-add [-h] [-e] [-n]
|
||||
[-s {PackageSource.Auto,PackageSource.Archive,PackageSource.AUR,PackageSource.Directory,PackageSource.Local,PackageSource.Remote}]
|
||||
[-s {PackageSource.Auto,PackageSource.Archive,PackageSource.AUR,PackageSource.Directory,PackageSource.Local,PackageSource.Remote,PackageSource.Repository}]
|
||||
[--without-dependencies]
|
||||
package [package ...]
|
||||
|
||||
@ -226,7 +229,7 @@ return non\-zero exit status if result is empty
|
||||
run update function after
|
||||
|
||||
.TP
|
||||
\fB\-s\fR {PackageSource.Auto,PackageSource.Archive,PackageSource.AUR,PackageSource.Directory,PackageSource.Local,PackageSource.Remote}, \fB\-\-source\fR {PackageSource.Auto,PackageSource.Archive,PackageSource.AUR,PackageSource.Directory,PackageSource.Local,PackageSource.Remote}
|
||||
\fB\-s\fR {PackageSource.Auto,PackageSource.Archive,PackageSource.AUR,PackageSource.Directory,PackageSource.Local,PackageSource.Remote,PackageSource.Repository}, \fB\-\-source\fR {PackageSource.Auto,PackageSource.Archive,PackageSource.AUR,PackageSource.Directory,PackageSource.Local,PackageSource.Remote,PackageSource.Repository}
|
||||
explicitly specify the package source for this command
|
||||
|
||||
.TP
|
||||
@ -235,7 +238,7 @@ do not add dependencies
|
||||
|
||||
.SH OPTIONS 'ahriman add'
|
||||
usage: ahriman package-add [-h] [-e] [-n]
|
||||
[-s {PackageSource.Auto,PackageSource.Archive,PackageSource.AUR,PackageSource.Directory,PackageSource.Local,PackageSource.Remote}]
|
||||
[-s {PackageSource.Auto,PackageSource.Archive,PackageSource.AUR,PackageSource.Directory,PackageSource.Local,PackageSource.Remote,PackageSource.Repository}]
|
||||
[--without-dependencies]
|
||||
package [package ...]
|
||||
|
||||
@ -254,7 +257,7 @@ return non\-zero exit status if result is empty
|
||||
run update function after
|
||||
|
||||
.TP
|
||||
\fB\-s\fR {PackageSource.Auto,PackageSource.Archive,PackageSource.AUR,PackageSource.Directory,PackageSource.Local,PackageSource.Remote}, \fB\-\-source\fR {PackageSource.Auto,PackageSource.Archive,PackageSource.AUR,PackageSource.Directory,PackageSource.Local,PackageSource.Remote}
|
||||
\fB\-s\fR {PackageSource.Auto,PackageSource.Archive,PackageSource.AUR,PackageSource.Directory,PackageSource.Local,PackageSource.Remote,PackageSource.Repository}, \fB\-\-source\fR {PackageSource.Auto,PackageSource.Archive,PackageSource.AUR,PackageSource.Directory,PackageSource.Local,PackageSource.Remote,PackageSource.Repository}
|
||||
explicitly specify the package source for this command
|
||||
|
||||
.TP
|
||||
@ -263,7 +266,7 @@ do not add dependencies
|
||||
|
||||
.SH OPTIONS 'ahriman package-update'
|
||||
usage: ahriman package-add [-h] [-e] [-n]
|
||||
[-s {PackageSource.Auto,PackageSource.Archive,PackageSource.AUR,PackageSource.Directory,PackageSource.Local,PackageSource.Remote}]
|
||||
[-s {PackageSource.Auto,PackageSource.Archive,PackageSource.AUR,PackageSource.Directory,PackageSource.Local,PackageSource.Remote,PackageSource.Repository}]
|
||||
[--without-dependencies]
|
||||
package [package ...]
|
||||
|
||||
@ -282,7 +285,7 @@ return non\-zero exit status if result is empty
|
||||
run update function after
|
||||
|
||||
.TP
|
||||
\fB\-s\fR {PackageSource.Auto,PackageSource.Archive,PackageSource.AUR,PackageSource.Directory,PackageSource.Local,PackageSource.Remote}, \fB\-\-source\fR {PackageSource.Auto,PackageSource.Archive,PackageSource.AUR,PackageSource.Directory,PackageSource.Local,PackageSource.Remote}
|
||||
\fB\-s\fR {PackageSource.Auto,PackageSource.Archive,PackageSource.AUR,PackageSource.Directory,PackageSource.Local,PackageSource.Remote,PackageSource.Repository}, \fB\-\-source\fR {PackageSource.Auto,PackageSource.Archive,PackageSource.AUR,PackageSource.Directory,PackageSource.Local,PackageSource.Remote,PackageSource.Repository}
|
||||
explicitly specify the package source for this command
|
||||
|
||||
.TP
|
||||
@ -615,6 +618,42 @@ generate repository report according to current settings
|
||||
target to generate report
|
||||
|
||||
|
||||
.SH OPTIONS 'ahriman repo-restore'
|
||||
usage: ahriman repo-restore [-h] [-e] [-n] [--without-dependencies]
|
||||
|
||||
restore repository from database file
|
||||
|
||||
|
||||
.TP
|
||||
\fB\-e\fR, \fB\-\-exit\-code\fR
|
||||
return non\-zero exit status if result is empty
|
||||
|
||||
.TP
|
||||
\fB\-n\fR, \fB\-\-now\fR
|
||||
run update function after
|
||||
|
||||
.TP
|
||||
\fB\-\-without\-dependencies\fR
|
||||
do not add dependencies
|
||||
|
||||
.SH OPTIONS 'ahriman restore'
|
||||
usage: ahriman repo-restore [-h] [-e] [-n] [--without-dependencies]
|
||||
|
||||
restore repository from database file
|
||||
|
||||
|
||||
.TP
|
||||
\fB\-e\fR, \fB\-\-exit\-code\fR
|
||||
return non\-zero exit status if result is empty
|
||||
|
||||
.TP
|
||||
\fB\-n\fR, \fB\-\-now\fR
|
||||
run update function after
|
||||
|
||||
.TP
|
||||
\fB\-\-without\-dependencies\fR
|
||||
do not add dependencies
|
||||
|
||||
.SH OPTIONS 'ahriman repo-setup'
|
||||
usage: ahriman repo-setup [-h] [--build-as-user BUILD_AS_USER] [--build-command BUILD_COMMAND]
|
||||
[--from-configuration FROM_CONFIGURATION] [--no-multilib] --packager PACKAGER --repository
|
||||
|
@ -1,7 +1,7 @@
|
||||
# Maintainer: Evgeniy Alekseev
|
||||
|
||||
pkgname='ahriman'
|
||||
pkgver=2.0.0rc2
|
||||
pkgver=2.0.0rc4
|
||||
pkgrel=1
|
||||
pkgdesc="ArcH Linux ReposItory MANager"
|
||||
arch=('any')
|
||||
|
@ -89,6 +89,7 @@ def _parser() -> argparse.ArgumentParser:
|
||||
_set_repo_rebuild_parser(subparsers)
|
||||
_set_repo_remove_unknown_parser(subparsers)
|
||||
_set_repo_report_parser(subparsers)
|
||||
_set_repo_restore_parser(subparsers)
|
||||
_set_repo_setup_parser(subparsers)
|
||||
_set_repo_sign_parser(subparsers)
|
||||
_set_repo_status_update_parser(subparsers)
|
||||
@ -409,6 +410,21 @@ def _set_repo_report_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
||||
return parser
|
||||
|
||||
|
||||
def _set_repo_restore_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
||||
"""
|
||||
add parser for package addition subcommand
|
||||
:param root: subparsers for the commands
|
||||
:return: created argument parser
|
||||
"""
|
||||
parser = root.add_parser("repo-restore", aliases=["restore"], help="restore repository",
|
||||
description="restore repository from database file", formatter_class=_formatter)
|
||||
parser.add_argument("-e", "--exit-code", help="return non-zero exit status if result is empty", action="store_true")
|
||||
parser.add_argument("-n", "--now", help="run update function after", action="store_true")
|
||||
parser.add_argument("--without-dependencies", help="do not add dependencies", action="store_true")
|
||||
parser.set_defaults(handler=handlers.Add, package=None, source=PackageSource.AUR)
|
||||
return parser
|
||||
|
||||
|
||||
def _set_repo_setup_parser(root: SubParserAction) -> argparse.ArgumentParser:
|
||||
"""
|
||||
add parser for setup subcommand
|
||||
|
@ -67,7 +67,8 @@ class Packages(Properties):
|
||||
:param without_dependencies: if set, dependency check will be disabled
|
||||
"""
|
||||
package = Package.load(source, PackageSource.AUR, self.repository.pacman, self.repository.aur_url)
|
||||
self.repository.database.build_queue_insert(package)
|
||||
|
||||
self.database.build_queue_insert(package)
|
||||
|
||||
with tmpdir() as local_path:
|
||||
Sources.load(local_path, package.git_url, self.database.patches_get(package.base))
|
||||
@ -93,7 +94,8 @@ class Packages(Properties):
|
||||
cache_dir = self.repository.paths.cache_for(package.base)
|
||||
shutil.copytree(Path(source), cache_dir) # copy package to store in caches
|
||||
Sources.init(cache_dir) # we need to run init command in directory where we do have permissions
|
||||
self.repository.database.build_queue_insert(package)
|
||||
|
||||
self.database.build_queue_insert(package)
|
||||
|
||||
self._process_dependencies(cache_dir, known_packages, without_dependencies)
|
||||
|
||||
|
@ -19,7 +19,7 @@
|
||||
#
|
||||
import argparse
|
||||
|
||||
from typing import Type
|
||||
from typing import List, Type
|
||||
|
||||
from ahriman.application.application import Application
|
||||
from ahriman.application.handlers.handler import Handler
|
||||
@ -43,10 +43,20 @@ class Add(Handler):
|
||||
:param unsafe: if set no user check will be performed before path creation
|
||||
"""
|
||||
application = Application(architecture, configuration, no_report, unsafe)
|
||||
application.add(args.package, args.source, args.without_dependencies)
|
||||
packages = Add.extract_packages(application) if args.package is None else args.package
|
||||
application.add(packages, args.source, args.without_dependencies)
|
||||
if not args.now:
|
||||
return
|
||||
|
||||
packages = application.updates(args.package, True, True, False, True, application.logger.info)
|
||||
packages = application.updates(packages, True, True, False, True, application.logger.info)
|
||||
result = application.update(packages)
|
||||
Add.check_if_empty(args.exit_code, result.is_empty)
|
||||
|
||||
@staticmethod
|
||||
def extract_packages(application: Application) -> List[str]:
|
||||
"""
|
||||
extract packages from database file
|
||||
:param application: application instance
|
||||
:return: list of packages which were stored in database
|
||||
"""
|
||||
return [package.base for (package, _) in application.database.packages_get()]
|
||||
|
@ -23,7 +23,8 @@ from dataclasses import fields
|
||||
from typing import Callable, Iterable, List, Tuple, Type
|
||||
|
||||
from ahriman.application.handlers.handler import Handler
|
||||
from ahriman.core.alpm.aur import AUR
|
||||
from ahriman.core.alpm.remote.aur import AUR
|
||||
from ahriman.core.alpm.remote.official import Official
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.core.exceptions import InvalidOption
|
||||
from ahriman.core.formatters.aur_printer import AurPrinter
|
||||
@ -50,8 +51,12 @@ class Search(Handler):
|
||||
:param no_report: force disable reporting
|
||||
:param unsafe: if set no user check will be performed before path creation
|
||||
"""
|
||||
packages_list = AUR.multisearch(*args.search)
|
||||
Search.check_if_empty(args.exit_code, not packages_list)
|
||||
official_packages_list = Official.multisearch(*args.search)
|
||||
aur_packages_list = AUR.multisearch(*args.search)
|
||||
Search.check_if_empty(args.exit_code, not official_packages_list and not aur_packages_list)
|
||||
|
||||
for packages_list in (official_packages_list, aur_packages_list):
|
||||
# keep sorting by packages source
|
||||
for package in Search.sort(packages_list, args.sort_by):
|
||||
AurPrinter(package).print(args.info)
|
||||
|
||||
|
19
src/ahriman/core/alpm/remote/__init__.py
Normal file
19
src/ahriman/core/alpm/remote/__init__.py
Normal file
@ -0,0 +1,19 @@
|
||||
#
|
||||
# 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/>.
|
||||
#
|
@ -17,24 +17,21 @@
|
||||
# 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 __future__ import annotations
|
||||
|
||||
import logging
|
||||
import requests
|
||||
|
||||
from typing import Any, Dict, List, Optional, Type
|
||||
from typing import Any, Dict, List, Optional
|
||||
|
||||
from ahriman.core.alpm.remote.remote import Remote
|
||||
from ahriman.core.exceptions import InvalidPackageInfo
|
||||
from ahriman.core.util import exception_response_text
|
||||
from ahriman.models.aur_package import AURPackage
|
||||
|
||||
|
||||
class AUR:
|
||||
class AUR(Remote):
|
||||
"""
|
||||
AUR RPC wrapper
|
||||
:cvar DEFAULT_RPC_URL: default AUR RPC url
|
||||
:cvar DEFAULT_RPC_VERSION: default AUR RPC version
|
||||
:ivar logger: class logger
|
||||
:ivar rpc_url: AUR RPC url
|
||||
:ivar rpc_version: AUR RPC version
|
||||
"""
|
||||
@ -48,46 +45,9 @@ class AUR:
|
||||
:param rpc_url: AUR RPC url
|
||||
:param rpc_version: AUR RPC version
|
||||
"""
|
||||
Remote.__init__(self)
|
||||
self.rpc_url = rpc_url or self.DEFAULT_RPC_URL
|
||||
self.rpc_version = rpc_version or self.DEFAULT_RPC_VERSION
|
||||
self.logger = logging.getLogger("build_details")
|
||||
|
||||
@classmethod
|
||||
def info(cls: Type[AUR], package_name: str) -> AURPackage:
|
||||
"""
|
||||
get package info by its name
|
||||
:param package_name: package name to search
|
||||
:return: package which match the package name
|
||||
"""
|
||||
return cls().package_info(package_name)
|
||||
|
||||
@classmethod
|
||||
def multisearch(cls: Type[AUR], *keywords: str) -> List[AURPackage]:
|
||||
"""
|
||||
search in AUR by using API with multiple words. This method is required in order to handle
|
||||
https://bugs.archlinux.org/task/49133. In addition short words will be dropped
|
||||
:param keywords: search terms, e.g. "ahriman", "is", "cool"
|
||||
:return: list of packages each of them matches all search terms
|
||||
"""
|
||||
instance = cls()
|
||||
packages: Dict[str, AURPackage] = {}
|
||||
for term in filter(lambda word: len(word) > 3, keywords):
|
||||
portion = instance.search(term)
|
||||
packages = {
|
||||
package.package_base: package
|
||||
for package in portion
|
||||
if package.package_base in packages or not packages
|
||||
}
|
||||
return list(packages.values())
|
||||
|
||||
@classmethod
|
||||
def search(cls: Type[AUR], *keywords: str) -> List[AURPackage]:
|
||||
"""
|
||||
search package in AUR web
|
||||
:param keywords: keywords to search
|
||||
:return: list of packages which match the criteria
|
||||
"""
|
||||
return cls().package_search(*keywords)
|
||||
|
||||
@staticmethod
|
||||
def parse_response(response: Dict[str, Any]) -> List[AURPackage]:
|
||||
@ -144,11 +104,10 @@ class AUR:
|
||||
packages = self.make_request("info", package_name)
|
||||
return next(package for package in packages if package.name == package_name)
|
||||
|
||||
def package_search(self, *keywords: str, by: str = "name-desc") -> List[AURPackage]:
|
||||
def package_search(self, *keywords: str) -> List[AURPackage]:
|
||||
"""
|
||||
search package in AUR web
|
||||
:param keywords: keywords to search
|
||||
:param by: search by the field
|
||||
:return: list of packages which match the criteria
|
||||
"""
|
||||
return self.make_request("search", *keywords, by=by)
|
||||
return self.make_request("search", *keywords, by="name-desc")
|
91
src/ahriman/core/alpm/remote/official.py
Normal file
91
src/ahriman/core/alpm/remote/official.py
Normal file
@ -0,0 +1,91 @@
|
||||
#
|
||||
# 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/>.
|
||||
#
|
||||
import requests
|
||||
|
||||
from typing import Any, Dict, List, Optional
|
||||
|
||||
from ahriman.core.alpm.remote.remote import Remote
|
||||
from ahriman.core.exceptions import InvalidPackageInfo
|
||||
from ahriman.core.util import exception_response_text
|
||||
from ahriman.models.aur_package import AURPackage
|
||||
|
||||
|
||||
class Official(Remote):
|
||||
"""
|
||||
official repository RPC wrapper
|
||||
:cvar DEFAULT_RPC_URL: default AUR RPC url
|
||||
:ivar rpc_url: AUR RPC url
|
||||
"""
|
||||
|
||||
DEFAULT_RPC_URL = "https://archlinux.org/packages/search/json"
|
||||
|
||||
def __init__(self, rpc_url: Optional[str] = None) -> None:
|
||||
"""
|
||||
default constructor
|
||||
:param rpc_url: AUR RPC url
|
||||
"""
|
||||
Remote.__init__(self)
|
||||
self.rpc_url = rpc_url or self.DEFAULT_RPC_URL
|
||||
|
||||
@staticmethod
|
||||
def parse_response(response: Dict[str, Any]) -> List[AURPackage]:
|
||||
"""
|
||||
parse RPC response to package list
|
||||
:param response: RPC response json
|
||||
:return: list of parsed packages
|
||||
"""
|
||||
if not response["valid"]:
|
||||
raise InvalidPackageInfo("API validation error")
|
||||
return [AURPackage.from_repo(package) for package in response["results"]]
|
||||
|
||||
def make_request(self, *args: str, by: str) -> List[AURPackage]:
|
||||
"""
|
||||
perform request to official repositories RPC
|
||||
:param args: list of arguments to be passed as args query parameter
|
||||
:param by: search by the field
|
||||
:return: response parsed to package list
|
||||
"""
|
||||
try:
|
||||
response = requests.get(self.rpc_url, params={by: args})
|
||||
response.raise_for_status()
|
||||
return self.parse_response(response.json())
|
||||
except requests.HTTPError as e:
|
||||
self.logger.exception("could not perform request: %s", exception_response_text(e))
|
||||
raise
|
||||
except Exception:
|
||||
self.logger.exception("could not perform request")
|
||||
raise
|
||||
|
||||
def package_info(self, package_name: str) -> AURPackage:
|
||||
"""
|
||||
get package info by its name
|
||||
:param package_name: package name to search
|
||||
:return: package which match the package name
|
||||
"""
|
||||
packages = self.make_request(package_name, by="name")
|
||||
return next(package for package in packages if package.name == package_name)
|
||||
|
||||
def package_search(self, *keywords: str) -> List[AURPackage]:
|
||||
"""
|
||||
search package in AUR web
|
||||
:param keywords: keywords to search
|
||||
:return: list of packages which match the criteria
|
||||
"""
|
||||
return self.make_request(*keywords, by="q")
|
92
src/ahriman/core/alpm/remote/remote.py
Normal file
92
src/ahriman/core/alpm/remote/remote.py
Normal file
@ -0,0 +1,92 @@
|
||||
#
|
||||
# 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 __future__ import annotations
|
||||
|
||||
import logging
|
||||
|
||||
from typing import Dict, List, Type
|
||||
|
||||
from ahriman.models.aur_package import AURPackage
|
||||
|
||||
|
||||
class Remote:
|
||||
"""
|
||||
base class for remote package search
|
||||
:ivar logger: class logger
|
||||
"""
|
||||
|
||||
def __init__(self) -> None:
|
||||
"""
|
||||
default constructor
|
||||
"""
|
||||
self.logger = logging.getLogger("build_details")
|
||||
|
||||
@classmethod
|
||||
def info(cls: Type[Remote], package_name: str) -> AURPackage:
|
||||
"""
|
||||
get package info by its name
|
||||
:param package_name: package name to search
|
||||
:return: package which match the package name
|
||||
"""
|
||||
return cls().package_info(package_name)
|
||||
|
||||
@classmethod
|
||||
def multisearch(cls: Type[Remote], *keywords: str) -> List[AURPackage]:
|
||||
"""
|
||||
search in remote repository by using API with multiple words. This method is required in order to handle
|
||||
https://bugs.archlinux.org/task/49133. In addition, short words will be dropped
|
||||
:param keywords: search terms, e.g. "ahriman", "is", "cool"
|
||||
:return: list of packages each of them matches all search terms
|
||||
"""
|
||||
instance = cls()
|
||||
packages: Dict[str, AURPackage] = {}
|
||||
for term in filter(lambda word: len(word) > 3, keywords):
|
||||
portion = instance.search(term)
|
||||
packages = {
|
||||
package.name: package # not mistake to group them by name
|
||||
for package in portion
|
||||
if package.name in packages or not packages
|
||||
}
|
||||
return list(packages.values())
|
||||
|
||||
@classmethod
|
||||
def search(cls: Type[Remote], *keywords: str) -> List[AURPackage]:
|
||||
"""
|
||||
search package in AUR web
|
||||
:param keywords: keywords to search
|
||||
:return: list of packages which match the criteria
|
||||
"""
|
||||
return cls().package_search(*keywords)
|
||||
|
||||
def package_info(self, package_name: str) -> AURPackage:
|
||||
"""
|
||||
get package info by its name
|
||||
:param package_name: package name to search
|
||||
:return: package which match the package name
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
def package_search(self, *keywords: str) -> List[AURPackage]:
|
||||
"""
|
||||
search package in AUR web
|
||||
:param keywords: keywords to search
|
||||
:return: list of packages which match the criteria
|
||||
"""
|
||||
raise NotImplementedError
|
@ -20,9 +20,9 @@
|
||||
from sqlite3 import Connection
|
||||
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.core.database.data.package_statuses import migrate_package_statuses
|
||||
from ahriman.core.database.data.patches import migrate_patches
|
||||
from ahriman.core.database.data.users import migrate_users_data
|
||||
from ahriman.core.database.data.package_statuses import migrate_package_statuses
|
||||
from ahriman.models.migration_result import MigrationResult
|
||||
from ahriman.models.repository_paths import RepositoryPaths
|
||||
|
||||
@ -37,7 +37,7 @@ def migrate_data(result: MigrationResult, connection: Connection,
|
||||
:param paths: repository paths instance
|
||||
"""
|
||||
# initial data migration
|
||||
if result.old_version == 0:
|
||||
if result.old_version <= 0:
|
||||
migrate_package_statuses(connection, paths)
|
||||
migrate_users_data(connection, configuration)
|
||||
migrate_patches(connection, paths)
|
||||
migrate_users_data(connection, configuration)
|
||||
|
@ -17,8 +17,6 @@
|
||||
# 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 __future__ import annotations
|
||||
|
||||
from sqlite3 import Connection
|
||||
from typing import List, Optional
|
||||
|
||||
@ -75,7 +73,7 @@ class AuthOperations(Operations):
|
||||
|
||||
def user_update(self, user: User) -> None:
|
||||
"""
|
||||
get user by username
|
||||
update user by username
|
||||
:param user: user descriptor
|
||||
"""
|
||||
def run(connection: Connection) -> None:
|
||||
|
@ -22,6 +22,7 @@ from __future__ import annotations
|
||||
import json
|
||||
import sqlite3
|
||||
|
||||
from pathlib import Path
|
||||
from sqlite3 import Connection
|
||||
from typing import Type
|
||||
|
||||
@ -46,10 +47,20 @@ class SQLite(AuthOperations, BuildOperations, PackageOperations, PatchOperations
|
||||
:param configuration: configuration instance
|
||||
:return: fully initialized instance of the database
|
||||
"""
|
||||
database = cls(configuration.getpath("settings", "database"))
|
||||
path = cls.database_path(configuration)
|
||||
database = cls(path)
|
||||
database.init(configuration)
|
||||
return database
|
||||
|
||||
@staticmethod
|
||||
def database_path(configuration: Configuration) -> Path:
|
||||
"""
|
||||
read database from configuration
|
||||
:param configuration: configuration instance
|
||||
:return: database path according to the configuration
|
||||
"""
|
||||
return configuration.getpath("settings", "database")
|
||||
|
||||
def init(self, configuration: Configuration) -> None:
|
||||
"""
|
||||
perform database migrations
|
||||
|
@ -116,6 +116,18 @@ def filter_json(source: Dict[str, Any], known_fields: Iterable[str]) -> Dict[str
|
||||
return {key: value for key, value in source.items() if key in known_fields and value is not None}
|
||||
|
||||
|
||||
def full_version(epoch: Union[str, int, None], pkgver: str, pkgrel: str) -> str:
|
||||
"""
|
||||
generate full version from components
|
||||
:param epoch: package epoch if any
|
||||
:param pkgver: package version
|
||||
:param pkgrel: package release version (arch linux specific)
|
||||
:return: generated version
|
||||
"""
|
||||
prefix = f"{epoch}:" if epoch else ""
|
||||
return f"{prefix}{pkgver}-{pkgrel}"
|
||||
|
||||
|
||||
def package_like(filename: Path) -> bool:
|
||||
"""
|
||||
check if file looks like package
|
||||
|
@ -25,7 +25,7 @@ import inflection
|
||||
from dataclasses import dataclass, field, fields
|
||||
from typing import Any, Callable, Dict, List, Optional, Type
|
||||
|
||||
from ahriman.core.util import filter_json
|
||||
from ahriman.core.util import filter_json, full_version
|
||||
|
||||
|
||||
@dataclass
|
||||
@ -59,12 +59,12 @@ class AURPackage:
|
||||
package_base_id: int
|
||||
package_base: str
|
||||
version: str
|
||||
description: str
|
||||
num_votes: int
|
||||
popularity: float
|
||||
first_submitted: datetime.datetime
|
||||
last_modified: datetime.datetime
|
||||
url_path: str
|
||||
description: str = "" # despite the fact that the field is required some packages don't have it
|
||||
url: Optional[str] = None
|
||||
out_of_date: Optional[datetime.datetime] = None
|
||||
maintainer: Optional[str] = None
|
||||
@ -88,6 +88,39 @@ class AURPackage:
|
||||
properties = cls.convert(dump)
|
||||
return cls(**filter_json(properties, known_fields))
|
||||
|
||||
@classmethod
|
||||
def from_repo(cls: Type[AURPackage], dump: Dict[str, Any]) -> AURPackage:
|
||||
"""
|
||||
construct package descriptor from official repository RPC properties
|
||||
:param dump: json dump body
|
||||
:return: AUR package descriptor
|
||||
"""
|
||||
return cls(
|
||||
id=0,
|
||||
name=dump["pkgname"],
|
||||
package_base_id=0,
|
||||
package_base=dump["pkgbase"],
|
||||
version=full_version(dump["epoch"], dump["pkgver"], dump["pkgrel"]),
|
||||
description=dump["pkgdesc"],
|
||||
num_votes=0,
|
||||
popularity=0.0,
|
||||
first_submitted=datetime.datetime.utcfromtimestamp(0),
|
||||
last_modified=datetime.datetime.strptime(dump["last_update"], "%Y-%m-%dT%H:%M:%S.%fZ"),
|
||||
url_path="",
|
||||
url=dump["url"],
|
||||
out_of_date=datetime.datetime.strptime(
|
||||
dump["flag_date"],
|
||||
"%Y-%m-%dT%H:%M:%S.%fZ") if dump["flag_date"] is not None else None,
|
||||
maintainer=next(iter(dump["maintainers"]), None),
|
||||
depends=dump["depends"],
|
||||
make_depends=dump["makedepends"],
|
||||
opt_depends=dump["optdepends"],
|
||||
conflicts=dump["conflicts"],
|
||||
provides=dump["provides"],
|
||||
license=dump["licenses"],
|
||||
keywords=[],
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def convert(descriptor: Dict[str, Any]) -> Dict[str, Any]:
|
||||
"""
|
||||
|
@ -26,12 +26,13 @@ from dataclasses import asdict, dataclass
|
||||
from pathlib import Path
|
||||
from pyalpm import vercmp # type: ignore
|
||||
from srcinfo.parse import parse_srcinfo # type: ignore
|
||||
from typing import Any, Dict, Iterable, List, Optional, Set, Type
|
||||
from typing import Any, Dict, Iterable, List, Set, Type
|
||||
|
||||
from ahriman.core.alpm.aur import AUR
|
||||
from ahriman.core.alpm.pacman import Pacman
|
||||
from ahriman.core.alpm.remote.aur import AUR
|
||||
from ahriman.core.alpm.remote.official import Official
|
||||
from ahriman.core.exceptions import InvalidPackageInfo
|
||||
from ahriman.core.util import check_output
|
||||
from ahriman.core.util import check_output, full_version
|
||||
from ahriman.models.package_description import PackageDescription
|
||||
from ahriman.models.package_source import PackageSource
|
||||
from ahriman.models.repository_paths import RepositoryPaths
|
||||
@ -144,7 +145,7 @@ class Package:
|
||||
if errors:
|
||||
raise InvalidPackageInfo(errors)
|
||||
packages = {key: PackageDescription() for key in srcinfo["packages"]}
|
||||
version = cls.full_version(srcinfo.get("epoch"), srcinfo["pkgver"], srcinfo["pkgrel"])
|
||||
version = full_version(srcinfo.get("epoch"), srcinfo["pkgver"], srcinfo["pkgrel"])
|
||||
|
||||
return cls(srcinfo["pkgbase"], version, aur_url, packages)
|
||||
|
||||
@ -165,6 +166,17 @@ class Package:
|
||||
aur_url=dump["aur_url"],
|
||||
packages=packages)
|
||||
|
||||
@classmethod
|
||||
def from_official(cls: Type[Package], name: str, aur_url: str) -> Package:
|
||||
"""
|
||||
construct package properties from official repository page
|
||||
:param name: package name (either base or normal name)
|
||||
:param aur_url: AUR root url
|
||||
:return: package properties
|
||||
"""
|
||||
package = Official.info(name)
|
||||
return cls(package.package_base, package.version, aur_url, {package.name: PackageDescription()})
|
||||
|
||||
@classmethod
|
||||
def load(cls: Type[Package], package: str, source: PackageSource, pacman: Pacman, aur_url: str) -> Package:
|
||||
"""
|
||||
@ -183,6 +195,8 @@ class Package:
|
||||
return cls.from_aur(package, aur_url)
|
||||
if resolved_source == PackageSource.Local:
|
||||
return cls.from_build(Path(package), aur_url)
|
||||
if resolved_source == PackageSource.Repository:
|
||||
return cls.from_official(package, aur_url)
|
||||
raise InvalidPackageInfo(f"Unsupported local package source {resolved_source}")
|
||||
except InvalidPackageInfo:
|
||||
raise
|
||||
@ -197,35 +211,25 @@ class Package:
|
||||
:return: list of package dependencies including makedepends array, but excluding packages from this base
|
||||
"""
|
||||
# additional function to remove versions from dependencies
|
||||
def trim_version(name: str) -> str:
|
||||
def extract_packages(raw_packages_list: List[str]) -> Set[str]:
|
||||
return {trim_version(package_name) for package_name in raw_packages_list}
|
||||
|
||||
def trim_version(package_name: str) -> str:
|
||||
for symbol in ("<", "=", ">"):
|
||||
name = name.split(symbol)[0]
|
||||
return name
|
||||
package_name = package_name.split(symbol)[0]
|
||||
return package_name
|
||||
|
||||
srcinfo, errors = parse_srcinfo((path / ".SRCINFO").read_text())
|
||||
if errors:
|
||||
raise InvalidPackageInfo(errors)
|
||||
makedepends = srcinfo.get("makedepends", [])
|
||||
makedepends = extract_packages(srcinfo.get("makedepends", []))
|
||||
# sum over each package
|
||||
depends: List[str] = srcinfo.get("depends", [])
|
||||
depends = extract_packages(srcinfo.get("depends", []))
|
||||
for package in srcinfo["packages"].values():
|
||||
depends.extend(package.get("depends", []))
|
||||
depends |= extract_packages(package.get("depends", []))
|
||||
# we are not interested in dependencies inside pkgbase
|
||||
packages = set(srcinfo["packages"].keys())
|
||||
full_list = set(depends + makedepends) - packages
|
||||
return {trim_version(package_name) for package_name in full_list}
|
||||
|
||||
@staticmethod
|
||||
def full_version(epoch: Optional[str], pkgver: str, pkgrel: str) -> str:
|
||||
"""
|
||||
generate full version from components
|
||||
:param epoch: package epoch if any
|
||||
:param pkgver: package version
|
||||
:param pkgrel: package release version (arch linux specific)
|
||||
:return: generated version
|
||||
"""
|
||||
prefix = f"{epoch}:" if epoch else ""
|
||||
return f"{prefix}{pkgver}-{pkgrel}"
|
||||
return (depends | makedepends) - packages
|
||||
|
||||
def actual_version(self, paths: RepositoryPaths) -> str:
|
||||
"""
|
||||
@ -252,7 +256,7 @@ class Package:
|
||||
if errors:
|
||||
raise InvalidPackageInfo(errors)
|
||||
|
||||
return self.full_version(srcinfo.get("epoch"), srcinfo["pkgver"], srcinfo["pkgrel"])
|
||||
return full_version(srcinfo.get("epoch"), srcinfo["pkgver"], srcinfo["pkgrel"])
|
||||
except Exception:
|
||||
logger.exception("cannot determine version of VCS package, make sure that you have VCS tools installed")
|
||||
|
||||
|
@ -35,6 +35,7 @@ class PackageSource(Enum):
|
||||
:cvar Directory: source is a directory which contains packages
|
||||
:cvar Local: source is locally stored PKGBUILD
|
||||
:cvar Remote: source is remote (http, ftp etc) link
|
||||
:cvar Repository: source is official repository
|
||||
"""
|
||||
|
||||
Auto = "auto"
|
||||
@ -43,6 +44,7 @@ class PackageSource(Enum):
|
||||
Directory = "directory"
|
||||
Local = "local"
|
||||
Remote = "remote"
|
||||
Repository = "repository"
|
||||
|
||||
def resolve(self, source: str) -> PackageSource:
|
||||
"""
|
||||
|
@ -17,4 +17,4 @@
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
__version__ = "2.0.0rc2"
|
||||
__version__ = "2.0.0rc4"
|
||||
|
@ -20,7 +20,7 @@
|
||||
from aiohttp.web import HTTPNotFound, Response, json_response
|
||||
from typing import Callable, List
|
||||
|
||||
from ahriman.core.alpm.aur import AUR
|
||||
from ahriman.core.alpm.remote.aur import AUR
|
||||
from ahriman.models.aur_package import AURPackage
|
||||
from ahriman.models.user_access import UserAccess
|
||||
from ahriman.web.views.base import BaseView
|
||||
|
@ -21,7 +21,7 @@ def test_finalize(application_packages: Packages) -> None:
|
||||
|
||||
def test_known_packages(application_packages: Packages) -> None:
|
||||
"""
|
||||
must raise NotImplemented for missing finalize method
|
||||
must raise NotImplemented for missing known_packages method
|
||||
"""
|
||||
with pytest.raises(NotImplementedError):
|
||||
application_packages._known_packages()
|
||||
@ -42,17 +42,17 @@ def test_add_aur(application_packages: Packages, package_ahriman: Package, mocke
|
||||
must add package from AUR
|
||||
"""
|
||||
mocker.patch("ahriman.models.package.Package.load", return_value=package_ahriman)
|
||||
insert_mock = mocker.patch("ahriman.core.database.sqlite.SQLite.build_queue_insert")
|
||||
load_mock = mocker.patch("ahriman.core.build_tools.sources.Sources.load")
|
||||
dependencies_mock = mocker.patch("ahriman.application.application.packages.Packages._process_dependencies")
|
||||
build_queue_mock = mocker.patch("ahriman.core.database.sqlite.SQLite.build_queue_insert")
|
||||
|
||||
application_packages._add_aur(package_ahriman.base, set(), False)
|
||||
insert_mock.assert_called_once_with(package_ahriman)
|
||||
load_mock.assert_called_once_with(
|
||||
pytest.helpers.anyvar(int),
|
||||
package_ahriman.git_url,
|
||||
pytest.helpers.anyvar(int))
|
||||
dependencies_mock.assert_called_once_with(pytest.helpers.anyvar(int), set(), False)
|
||||
build_queue_mock.assert_called_once_with(package_ahriman)
|
||||
|
||||
|
||||
def test_add_directory(application_packages: Packages, package_ahriman: Package, mocker: MockerFixture) -> None:
|
||||
@ -75,16 +75,16 @@ def test_add_local(application_packages: Packages, package_ahriman: Package, moc
|
||||
"""
|
||||
mocker.patch("ahriman.models.package.Package.load", return_value=package_ahriman)
|
||||
init_mock = mocker.patch("ahriman.core.build_tools.sources.Sources.init")
|
||||
insert_mock = mocker.patch("ahriman.core.database.sqlite.SQLite.build_queue_insert")
|
||||
copytree_mock = mocker.patch("shutil.copytree")
|
||||
dependencies_mock = mocker.patch("ahriman.application.application.packages.Packages._process_dependencies")
|
||||
build_queue_mock = mocker.patch("ahriman.core.database.sqlite.SQLite.build_queue_insert")
|
||||
|
||||
application_packages._add_local(package_ahriman.base, set(), False)
|
||||
copytree_mock.assert_called_once_with(
|
||||
Path(package_ahriman.base), application_packages.repository.paths.cache_for(package_ahriman.base))
|
||||
init_mock.assert_called_once_with(application_packages.repository.paths.cache_for(package_ahriman.base))
|
||||
insert_mock.assert_called_once_with(package_ahriman)
|
||||
dependencies_mock.assert_called_once_with(pytest.helpers.anyvar(int), set(), False)
|
||||
build_queue_mock.assert_called_once_with(package_ahriman)
|
||||
|
||||
|
||||
def test_add_remote(application_packages: Packages, package_description_ahriman: PackageDescription,
|
||||
|
@ -3,6 +3,7 @@ import pytest
|
||||
|
||||
from pytest_mock import MockerFixture
|
||||
|
||||
from ahriman.application.application import Application
|
||||
from ahriman.application.handlers import Add
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.models.package import Package
|
||||
@ -36,6 +37,20 @@ def test_run(args: argparse.Namespace, configuration: Configuration, mocker: Moc
|
||||
application_mock.assert_called_once_with(args.package, args.source, args.without_dependencies)
|
||||
|
||||
|
||||
def test_run_extract_packages(args: argparse.Namespace, configuration: Configuration, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must run command
|
||||
"""
|
||||
args = _default_args(args)
|
||||
args.package = None
|
||||
mocker.patch("ahriman.models.repository_paths.RepositoryPaths.tree_create")
|
||||
mocker.patch("ahriman.application.application.Application.add")
|
||||
extract_mock = mocker.patch("ahriman.application.handlers.Add.extract_packages", return_value=[])
|
||||
|
||||
Add.run(args, "x86_64", configuration, True, False)
|
||||
extract_mock.assert_called_once_with(pytest.helpers.anyvar(int))
|
||||
|
||||
|
||||
def test_run_with_updates(args: argparse.Namespace, configuration: Configuration,
|
||||
package_ahriman: Package, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
@ -72,3 +87,12 @@ def test_run_empty_exception(args: argparse.Namespace, configuration: Configurat
|
||||
|
||||
Add.run(args, "x86_64", configuration, True, False)
|
||||
check_mock.assert_called_once_with(True, True)
|
||||
|
||||
|
||||
def test_extract_packages(application: Application, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must extract packages from database
|
||||
"""
|
||||
packages_mock = mocker.patch("ahriman.core.database.sqlite.SQLite.packages_get")
|
||||
Add.extract_packages(application)
|
||||
packages_mock.assert_called_once_with()
|
||||
|
@ -3,6 +3,7 @@ import dataclasses
|
||||
import pytest
|
||||
|
||||
from pytest_mock import MockerFixture
|
||||
from unittest import mock
|
||||
|
||||
from ahriman.application.handlers import Search
|
||||
from ahriman.core.configuration import Configuration
|
||||
@ -29,23 +30,27 @@ def test_run(args: argparse.Namespace, configuration: Configuration, aur_package
|
||||
must run command
|
||||
"""
|
||||
args = _default_args(args)
|
||||
search_mock = mocker.patch("ahriman.core.alpm.aur.AUR.multisearch", return_value=[aur_package_ahriman])
|
||||
aur_search_mock = mocker.patch("ahriman.core.alpm.remote.aur.AUR.multisearch", return_value=[aur_package_ahriman])
|
||||
official_search_mock = mocker.patch("ahriman.core.alpm.remote.official.Official.multisearch",
|
||||
return_value=[aur_package_ahriman])
|
||||
check_mock = mocker.patch("ahriman.application.handlers.handler.Handler.check_if_empty")
|
||||
print_mock = mocker.patch("ahriman.core.formatters.printer.Printer.print")
|
||||
|
||||
Search.run(args, "x86_64", configuration, True, False)
|
||||
search_mock.assert_called_once_with("ahriman")
|
||||
aur_search_mock.assert_called_once_with("ahriman")
|
||||
official_search_mock.assert_called_once_with("ahriman")
|
||||
check_mock.assert_called_once_with(False, False)
|
||||
print_mock.assert_called_once_with(False)
|
||||
print_mock.assert_has_calls([mock.call(False), mock.call(False)])
|
||||
|
||||
|
||||
def test_run_empty_exception(args: argparse.Namespace, configuration: Configuration, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must run command
|
||||
must raise ExitCode exception on empty result list
|
||||
"""
|
||||
args = _default_args(args)
|
||||
args.exit_code = True
|
||||
mocker.patch("ahriman.core.alpm.aur.AUR.multisearch", return_value=[])
|
||||
mocker.patch("ahriman.core.alpm.remote.aur.AUR.multisearch", return_value=[])
|
||||
mocker.patch("ahriman.core.alpm.remote.official.Official.multisearch", return_value=[])
|
||||
mocker.patch("ahriman.core.formatters.printer.Printer.print")
|
||||
check_mock = mocker.patch("ahriman.application.handlers.handler.Handler.check_if_empty")
|
||||
|
||||
@ -59,11 +64,15 @@ def test_run_sort(args: argparse.Namespace, configuration: Configuration, aur_pa
|
||||
must run command with sorting
|
||||
"""
|
||||
args = _default_args(args)
|
||||
mocker.patch("ahriman.core.alpm.aur.AUR.multisearch", return_value=[aur_package_ahriman])
|
||||
mocker.patch("ahriman.core.alpm.remote.aur.AUR.multisearch", return_value=[aur_package_ahriman])
|
||||
mocker.patch("ahriman.core.alpm.remote.official.Official.multisearch", return_value=[])
|
||||
sort_mock = mocker.patch("ahriman.application.handlers.search.Search.sort")
|
||||
|
||||
Search.run(args, "x86_64", configuration, True, False)
|
||||
sort_mock.assert_called_once_with([aur_package_ahriman], "name")
|
||||
sort_mock.assert_has_calls([
|
||||
mock.call([], "name"), mock.call().__iter__(),
|
||||
mock.call([aur_package_ahriman], "name"), mock.call().__iter__()
|
||||
])
|
||||
|
||||
|
||||
def test_run_sort_by(args: argparse.Namespace, configuration: Configuration, aur_package_ahriman: AURPackage,
|
||||
@ -73,11 +82,15 @@ def test_run_sort_by(args: argparse.Namespace, configuration: Configuration, aur
|
||||
"""
|
||||
args = _default_args(args)
|
||||
args.sort_by = "field"
|
||||
mocker.patch("ahriman.core.alpm.aur.AUR.multisearch", return_value=[aur_package_ahriman])
|
||||
mocker.patch("ahriman.core.alpm.remote.aur.AUR.multisearch", return_value=[aur_package_ahriman])
|
||||
mocker.patch("ahriman.core.alpm.remote.official.Official.multisearch", return_value=[])
|
||||
sort_mock = mocker.patch("ahriman.application.handlers.search.Search.sort")
|
||||
|
||||
Search.run(args, "x86_64", configuration, True, False)
|
||||
sort_mock.assert_called_once_with([aur_package_ahriman], "field")
|
||||
sort_mock.assert_has_calls([
|
||||
mock.call([], "field"), mock.call().__iter__(),
|
||||
mock.call([aur_package_ahriman], "field"), mock.call().__iter__()
|
||||
])
|
||||
|
||||
|
||||
def test_sort(aur_package_ahriman: AURPackage) -> None:
|
||||
|
@ -62,7 +62,7 @@ def test_run_empty_exception(args: argparse.Namespace, configuration: Configurat
|
||||
def test_run_verbose(args: argparse.Namespace, configuration: Configuration, package_ahriman: Package,
|
||||
mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must run command
|
||||
must run command with detailed info
|
||||
"""
|
||||
args = _default_args(args)
|
||||
args.info = True
|
||||
|
@ -59,7 +59,7 @@ def test_check_unsafe() -> None:
|
||||
|
||||
def test_check_unsafe_safe() -> None:
|
||||
"""
|
||||
must check if command is unsafe
|
||||
must check if command is safe
|
||||
"""
|
||||
UnsafeCommands.check_unsafe("package-status", ["repo-clean"], _parser())
|
||||
|
||||
|
@ -34,7 +34,7 @@ def test_run(args: argparse.Namespace, configuration: Configuration, mocker: Moc
|
||||
|
||||
def test_disallow_auto_architecture_run() -> None:
|
||||
"""
|
||||
must not allow multi architecture run
|
||||
must not allow auto architecture run
|
||||
"""
|
||||
assert not Web.ALLOW_AUTO_ARCHITECTURE_RUN
|
||||
|
||||
|
@ -6,6 +6,7 @@ from pytest_mock import MockerFixture
|
||||
from ahriman.application.handlers import Handler
|
||||
from ahriman.models.action import Action
|
||||
from ahriman.models.build_status import BuildStatusEnum
|
||||
from ahriman.models.package_source import PackageSource
|
||||
from ahriman.models.sign_settings import SignSettings
|
||||
from ahriman.models.user_access import UserAccess
|
||||
|
||||
@ -339,6 +340,25 @@ def test_subparsers_repo_report_architecture(parser: argparse.ArgumentParser) ->
|
||||
assert args.architecture == ["x86_64"]
|
||||
|
||||
|
||||
def test_subparsers_repo_restore(parser: argparse.ArgumentParser) -> None:
|
||||
"""
|
||||
repo-restore command must imply package and source
|
||||
"""
|
||||
args = parser.parse_args(["repo-restore"])
|
||||
assert args.package is None
|
||||
assert args.source == PackageSource.AUR
|
||||
|
||||
|
||||
def test_subparsers_repo_restore_architecture(parser: argparse.ArgumentParser) -> None:
|
||||
"""
|
||||
repo-restore command must correctly parse architecture list
|
||||
"""
|
||||
args = parser.parse_args(["repo-restore"])
|
||||
assert args.architecture is None
|
||||
args = parser.parse_args(["-a", "x86_64", "repo-restore"])
|
||||
assert args.architecture == ["x86_64"]
|
||||
|
||||
|
||||
def test_subparsers_repo_setup(parser: argparse.ArgumentParser) -> None:
|
||||
"""
|
||||
repo-setup command must imply lock, no-report, quiet and unsafe
|
||||
|
@ -124,6 +124,50 @@ def aur_package_ahriman() -> AURPackage:
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def aur_package_akonadi() -> AURPackage:
|
||||
"""
|
||||
fixture for AUR package
|
||||
:return: AUR package test instance
|
||||
"""
|
||||
return AURPackage(
|
||||
id=0,
|
||||
name="akonadi",
|
||||
package_base_id=0,
|
||||
package_base="akonadi",
|
||||
version="21.12.3-2",
|
||||
description="PIM layer, which provides an asynchronous API to access all kind of PIM data",
|
||||
num_votes=0,
|
||||
popularity=0,
|
||||
first_submitted=datetime.datetime(1970, 1, 1, 0, 0, 0),
|
||||
last_modified=datetime.datetime(2022, 3, 6, 8, 39, 50, 610000),
|
||||
url_path="",
|
||||
url="https://kontact.kde.org",
|
||||
out_of_date=None,
|
||||
maintainer="felixonmars",
|
||||
depends=[
|
||||
"libakonadi",
|
||||
"mariadb",
|
||||
],
|
||||
make_depends=[
|
||||
"boost",
|
||||
"doxygen",
|
||||
"extra-cmake-modules",
|
||||
"kaccounts-integration",
|
||||
"kitemmodels",
|
||||
"postgresql",
|
||||
"qt5-tools",
|
||||
],
|
||||
opt_depends=[
|
||||
"postgresql: PostgreSQL backend",
|
||||
],
|
||||
conflicts=[],
|
||||
provides=[],
|
||||
license=["LGPL"],
|
||||
keywords=[],
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def auth(configuration: Configuration) -> Auth:
|
||||
"""
|
||||
@ -264,9 +308,7 @@ def repository_paths(configuration: Configuration) -> RepositoryPaths:
|
||||
:param configuration: configuration fixture
|
||||
:return: repository paths test instance
|
||||
"""
|
||||
return RepositoryPaths(
|
||||
architecture="x86_64",
|
||||
root=configuration.getpath("repository", "root"))
|
||||
return configuration.repository_paths
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
|
@ -1,12 +0,0 @@
|
||||
import pytest
|
||||
|
||||
from ahriman.core.alpm.aur import AUR
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def aur() -> AUR:
|
||||
"""
|
||||
aur helper fixture
|
||||
:return: aur helper instance
|
||||
"""
|
||||
return AUR()
|
32
tests/ahriman/core/alpm/remote/conftest.py
Normal file
32
tests/ahriman/core/alpm/remote/conftest.py
Normal file
@ -0,0 +1,32 @@
|
||||
import pytest
|
||||
|
||||
from ahriman.core.alpm.remote.aur import AUR
|
||||
from ahriman.core.alpm.remote.official import Official
|
||||
from ahriman.core.alpm.remote.remote import Remote
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def aur() -> AUR:
|
||||
"""
|
||||
aur helper fixture
|
||||
:return: aur helper instance
|
||||
"""
|
||||
return AUR()
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def official() -> Official:
|
||||
"""
|
||||
official repository fixture
|
||||
:return: official repository helper instance
|
||||
"""
|
||||
return Official()
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def remote() -> Remote:
|
||||
"""
|
||||
official repository fixture
|
||||
:return: official repository helper instance
|
||||
"""
|
||||
return Remote()
|
@ -4,10 +4,9 @@ import requests
|
||||
|
||||
from pathlib import Path
|
||||
from pytest_mock import MockerFixture
|
||||
from unittest import mock
|
||||
from unittest.mock import MagicMock
|
||||
|
||||
from ahriman.core.alpm.aur import AUR
|
||||
from ahriman.core.alpm.remote.aur import AUR
|
||||
from ahriman.core.exceptions import InvalidPackageInfo
|
||||
from ahriman.models.aur_package import AURPackage
|
||||
|
||||
@ -21,55 +20,6 @@ def _get_response(resource_path_root: Path) -> str:
|
||||
return (resource_path_root / "models" / "package_ahriman_aur").read_text()
|
||||
|
||||
|
||||
def test_info(mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must call info method
|
||||
"""
|
||||
info_mock = mocker.patch("ahriman.core.alpm.aur.AUR.package_info")
|
||||
AUR.info("ahriman")
|
||||
info_mock.assert_called_once_with("ahriman")
|
||||
|
||||
|
||||
def test_multisearch(aur_package_ahriman: AURPackage, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must search in AUR with multiple words
|
||||
"""
|
||||
terms = ["ahriman", "is", "cool"]
|
||||
search_mock = mocker.patch("ahriman.core.alpm.aur.AUR.search", return_value=[aur_package_ahriman])
|
||||
|
||||
assert AUR.multisearch(*terms) == [aur_package_ahriman]
|
||||
search_mock.assert_has_calls([mock.call("ahriman"), mock.call("cool")])
|
||||
|
||||
|
||||
def test_multisearch_empty(mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must return empty list if no long terms supplied
|
||||
"""
|
||||
terms = ["it", "is"]
|
||||
search_mock = mocker.patch("ahriman.core.alpm.aur.AUR.search")
|
||||
|
||||
assert AUR.multisearch(*terms) == []
|
||||
search_mock.assert_not_called()
|
||||
|
||||
|
||||
def test_multisearch_single(aur_package_ahriman: AURPackage, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must search in AUR with one word
|
||||
"""
|
||||
search_mock = mocker.patch("ahriman.core.alpm.aur.AUR.search", return_value=[aur_package_ahriman])
|
||||
assert AUR.multisearch("ahriman") == [aur_package_ahriman]
|
||||
search_mock.assert_called_once_with("ahriman")
|
||||
|
||||
|
||||
def test_search(mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must call search method
|
||||
"""
|
||||
search_mock = mocker.patch("ahriman.core.alpm.aur.AUR.package_search")
|
||||
AUR.search("ahriman")
|
||||
search_mock.assert_called_once_with("ahriman")
|
||||
|
||||
|
||||
def test_parse_response(aur_package_ahriman: AURPackage, resource_path_root: Path) -> None:
|
||||
"""
|
||||
must parse success response
|
||||
@ -87,7 +37,7 @@ def test_parse_response_error(resource_path_root: Path) -> None:
|
||||
AUR.parse_response(json.loads(response))
|
||||
|
||||
|
||||
def test_parse_response_unknown_error(resource_path_root: Path) -> None:
|
||||
def test_parse_response_unknown_error() -> None:
|
||||
"""
|
||||
must raise exception on invalid response with empty error message
|
||||
"""
|
||||
@ -159,7 +109,7 @@ def test_package_info(aur: AUR, aur_package_ahriman: AURPackage, mocker: MockerF
|
||||
"""
|
||||
must make request for info
|
||||
"""
|
||||
request_mock = mocker.patch("ahriman.core.alpm.aur.AUR.make_request", return_value=[aur_package_ahriman])
|
||||
request_mock = mocker.patch("ahriman.core.alpm.remote.aur.AUR.make_request", return_value=[aur_package_ahriman])
|
||||
assert aur.package_info(aur_package_ahriman.name) == aur_package_ahriman
|
||||
request_mock.assert_called_once_with("info", aur_package_ahriman.name)
|
||||
|
||||
@ -168,6 +118,6 @@ def test_package_search(aur: AUR, aur_package_ahriman: AURPackage, mocker: Mocke
|
||||
"""
|
||||
must make request for search
|
||||
"""
|
||||
request_mock = mocker.patch("ahriman.core.alpm.aur.AUR.make_request", return_value=[aur_package_ahriman])
|
||||
assert aur.package_search(aur_package_ahriman.name, by="name") == [aur_package_ahriman]
|
||||
request_mock.assert_called_once_with("search", aur_package_ahriman.name, by="name")
|
||||
request_mock = mocker.patch("ahriman.core.alpm.remote.aur.AUR.make_request", return_value=[aur_package_ahriman])
|
||||
assert aur.package_search(aur_package_ahriman.name) == [aur_package_ahriman]
|
||||
request_mock.assert_called_once_with("search", aur_package_ahriman.name, by="name-desc")
|
88
tests/ahriman/core/alpm/remote/test_official.py
Normal file
88
tests/ahriman/core/alpm/remote/test_official.py
Normal file
@ -0,0 +1,88 @@
|
||||
import json
|
||||
import pytest
|
||||
import requests
|
||||
|
||||
from pathlib import Path
|
||||
from pytest_mock import MockerFixture
|
||||
from unittest.mock import MagicMock
|
||||
|
||||
from ahriman.core.alpm.remote.official import Official
|
||||
from ahriman.core.exceptions import InvalidPackageInfo
|
||||
from ahriman.models.aur_package import AURPackage
|
||||
|
||||
|
||||
def _get_response(resource_path_root: Path) -> str:
|
||||
"""
|
||||
load response from resource file
|
||||
:param resource_path_root: path to resource root
|
||||
:return: response text
|
||||
"""
|
||||
return (resource_path_root / "models" / "package_akonadi_aur").read_text()
|
||||
|
||||
|
||||
def test_parse_response(aur_package_akonadi: AURPackage, resource_path_root: Path) -> None:
|
||||
"""
|
||||
must parse success response
|
||||
"""
|
||||
response = _get_response(resource_path_root)
|
||||
assert Official.parse_response(json.loads(response)) == [aur_package_akonadi]
|
||||
|
||||
|
||||
def test_parse_response_unknown_error(resource_path_root: Path) -> None:
|
||||
"""
|
||||
must raise exception on invalid response with empty error message
|
||||
"""
|
||||
response = (resource_path_root / "models" / "official_error").read_text()
|
||||
with pytest.raises(InvalidPackageInfo, match="API validation error"):
|
||||
Official.parse_response(json.loads(response))
|
||||
|
||||
|
||||
def test_make_request(official: Official, aur_package_akonadi: AURPackage,
|
||||
mocker: MockerFixture, resource_path_root: Path) -> None:
|
||||
"""
|
||||
must perform request to official repositories
|
||||
"""
|
||||
response_mock = MagicMock()
|
||||
response_mock.json.return_value = json.loads(_get_response(resource_path_root))
|
||||
request_mock = mocker.patch("requests.get", return_value=response_mock)
|
||||
|
||||
assert official.make_request("akonadi", by="q") == [aur_package_akonadi]
|
||||
request_mock.assert_called_once_with("https://archlinux.org/packages/search/json", params={"q": ("akonadi",)})
|
||||
|
||||
|
||||
def test_make_request_failed(official: Official, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must reraise generic exception
|
||||
"""
|
||||
mocker.patch("requests.get", side_effect=Exception())
|
||||
with pytest.raises(Exception):
|
||||
official.make_request("akonadi", by="q")
|
||||
|
||||
|
||||
def test_make_request_failed_http_error(official: Official, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must reraise http exception
|
||||
"""
|
||||
mocker.patch("requests.get", side_effect=requests.exceptions.HTTPError())
|
||||
with pytest.raises(requests.exceptions.HTTPError):
|
||||
official.make_request("akonadi", by="q")
|
||||
|
||||
|
||||
def test_package_info(official: Official, aur_package_akonadi: AURPackage, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must make request for info
|
||||
"""
|
||||
request_mock = mocker.patch("ahriman.core.alpm.remote.official.Official.make_request",
|
||||
return_value=[aur_package_akonadi])
|
||||
assert official.package_info(aur_package_akonadi.name) == aur_package_akonadi
|
||||
request_mock.assert_called_once_with(aur_package_akonadi.name, by="name")
|
||||
|
||||
|
||||
def test_package_search(official: Official, aur_package_akonadi: AURPackage, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must make request for search
|
||||
"""
|
||||
request_mock = mocker.patch("ahriman.core.alpm.remote.official.Official.make_request",
|
||||
return_value=[aur_package_akonadi])
|
||||
assert official.package_search(aur_package_akonadi.name) == [aur_package_akonadi]
|
||||
request_mock.assert_called_once_with(aur_package_akonadi.name, by="q")
|
72
tests/ahriman/core/alpm/remote/test_remote.py
Normal file
72
tests/ahriman/core/alpm/remote/test_remote.py
Normal file
@ -0,0 +1,72 @@
|
||||
import pytest
|
||||
|
||||
from pytest_mock import MockerFixture
|
||||
from unittest import mock
|
||||
|
||||
from ahriman.core.alpm.remote.remote import Remote
|
||||
from ahriman.models.aur_package import AURPackage
|
||||
|
||||
|
||||
def test_info(mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must call info method
|
||||
"""
|
||||
info_mock = mocker.patch("ahriman.core.alpm.remote.remote.Remote.package_info")
|
||||
Remote.info("ahriman")
|
||||
info_mock.assert_called_once_with("ahriman")
|
||||
|
||||
|
||||
def test_multisearch(aur_package_ahriman: AURPackage, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must search in AUR with multiple words
|
||||
"""
|
||||
terms = ["ahriman", "is", "cool"]
|
||||
search_mock = mocker.patch("ahriman.core.alpm.remote.remote.Remote.search", return_value=[aur_package_ahriman])
|
||||
|
||||
assert Remote.multisearch(*terms) == [aur_package_ahriman]
|
||||
search_mock.assert_has_calls([mock.call("ahriman"), mock.call("cool")])
|
||||
|
||||
|
||||
def test_multisearch_empty(mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must return empty list if no long terms supplied
|
||||
"""
|
||||
terms = ["it", "is"]
|
||||
search_mock = mocker.patch("ahriman.core.alpm.remote.remote.Remote.search")
|
||||
|
||||
assert Remote.multisearch(*terms) == []
|
||||
search_mock.assert_not_called()
|
||||
|
||||
|
||||
def test_multisearch_single(aur_package_ahriman: AURPackage, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must search in AUR with one word
|
||||
"""
|
||||
search_mock = mocker.patch("ahriman.core.alpm.remote.remote.Remote.search", return_value=[aur_package_ahriman])
|
||||
assert Remote.multisearch("ahriman") == [aur_package_ahriman]
|
||||
search_mock.assert_called_once_with("ahriman")
|
||||
|
||||
|
||||
def test_search(mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must call search method
|
||||
"""
|
||||
search_mock = mocker.patch("ahriman.core.alpm.remote.remote.Remote.package_search")
|
||||
Remote.search("ahriman")
|
||||
search_mock.assert_called_once_with("ahriman")
|
||||
|
||||
|
||||
def test_package_info(remote: Remote) -> None:
|
||||
"""
|
||||
must raise NotImplemented for missing package info method
|
||||
"""
|
||||
with pytest.raises(NotImplementedError):
|
||||
remote.package_info("package")
|
||||
|
||||
|
||||
def test_package_search(remote: Remote) -> None:
|
||||
"""
|
||||
must raise NotImplemented for missing package search method
|
||||
"""
|
||||
with pytest.raises(NotImplementedError):
|
||||
remote.package_search("package")
|
@ -13,10 +13,12 @@ def test_migrate_data_initial(connection: Connection, configuration: Configurati
|
||||
must perform initial migration
|
||||
"""
|
||||
packages = mocker.patch("ahriman.core.database.data.migrate_package_statuses")
|
||||
patches = mocker.patch("ahriman.core.database.data.migrate_patches")
|
||||
users = mocker.patch("ahriman.core.database.data.migrate_users_data")
|
||||
|
||||
migrate_data(MigrationResult(old_version=0, new_version=900), connection, configuration, repository_paths)
|
||||
packages.assert_called_once_with(connection, repository_paths)
|
||||
patches.assert_called_once_with(connection, repository_paths)
|
||||
users.assert_called_once_with(connection, configuration)
|
||||
|
||||
|
||||
|
@ -21,7 +21,7 @@ def test_sign_ascii(package_ahriman: Package) -> None:
|
||||
|
||||
def test_sign_utf8(package_ahriman: Package) -> None:
|
||||
"""
|
||||
must correctly generate sign in ascii
|
||||
must correctly generate sign in utf8
|
||||
"""
|
||||
with pytest.raises(UnicodeEncodeError):
|
||||
BuildPrinter(package_ahriman, is_success=True, use_utf=True).title().encode("ascii")
|
||||
@ -31,6 +31,6 @@ def test_sign_utf8(package_ahriman: Package) -> None:
|
||||
|
||||
def test_title(package_ahriman: Package) -> None:
|
||||
"""
|
||||
must return non empty title
|
||||
must return non-empty title
|
||||
"""
|
||||
assert BuildPrinter(package_ahriman, is_success=True, use_utf=False).title() is not None
|
||||
|
@ -115,7 +115,7 @@ def test_generate_with_built_and_full_path(
|
||||
result: Result,
|
||||
mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must generate report with built packages
|
||||
must generate report with built packages and full packages lists
|
||||
"""
|
||||
send_mock = mocker.patch("ahriman.core.report.email.Email._send")
|
||||
|
||||
|
@ -64,6 +64,8 @@ def test_process_remove_base(executor: Executor, package_ahriman: Package, mocke
|
||||
mocker.patch("ahriman.core.repository.executor.Executor.packages", return_value=[package_ahriman])
|
||||
tree_clear_mock = mocker.patch("ahriman.models.repository_paths.RepositoryPaths.tree_clear")
|
||||
repo_remove_mock = mocker.patch("ahriman.core.alpm.repo.Repo.remove")
|
||||
build_queue_mock = mocker.patch("ahriman.core.database.sqlite.SQLite.build_queue_clear")
|
||||
patches_mock = mocker.patch("ahriman.core.database.sqlite.SQLite.patches_remove")
|
||||
status_client_mock = mocker.patch("ahriman.core.status.client.Client.remove")
|
||||
|
||||
executor.process_remove([package_ahriman.base])
|
||||
@ -72,6 +74,8 @@ def test_process_remove_base(executor: Executor, package_ahriman: Package, mocke
|
||||
package_ahriman.base, package_ahriman.packages[package_ahriman.base].filepath)
|
||||
# must update status and remove package files
|
||||
tree_clear_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)
|
||||
status_client_mock.assert_called_once_with(package_ahriman.base)
|
||||
|
||||
|
||||
|
@ -26,7 +26,7 @@ def test_load_full_client(configuration: Configuration) -> None:
|
||||
|
||||
def test_load_full_client_from_address(configuration: Configuration) -> None:
|
||||
"""
|
||||
must load full client if settings set
|
||||
must load full client by using address
|
||||
"""
|
||||
configuration.set_option("web", "address", "http://localhost:8080")
|
||||
assert isinstance(Client.load(configuration), WebClient)
|
||||
|
@ -23,7 +23,7 @@ def test_ahriman_url(web_client: WebClient) -> None:
|
||||
|
||||
def test_status_url(web_client: WebClient) -> None:
|
||||
"""
|
||||
must generate service status url correctly
|
||||
must generate package status url correctly
|
||||
"""
|
||||
assert web_client._status_url.startswith(web_client.address)
|
||||
assert web_client._status_url.endswith("/status-api/v1/status")
|
||||
@ -67,7 +67,7 @@ def test_login_failed(web_client: WebClient, user: User, mocker: MockerFixture)
|
||||
|
||||
def test_login_failed_http_error(web_client: WebClient, user: User, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must suppress any exception happened during login
|
||||
must suppress HTTP exception happened during login
|
||||
"""
|
||||
web_client.user = user
|
||||
mocker.patch("requests.Session.post", side_effect=requests.exceptions.HTTPError())
|
||||
@ -112,7 +112,7 @@ def test_add_failed(web_client: WebClient, package_ahriman: Package, mocker: Moc
|
||||
|
||||
def test_add_failed_http_error(web_client: WebClient, package_ahriman: Package, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must suppress any exception happened during addition
|
||||
must suppress HTTP exception happened during addition
|
||||
"""
|
||||
mocker.patch("requests.Session.post", side_effect=requests.exceptions.HTTPError())
|
||||
web_client.add(package_ahriman, BuildStatusEnum.Unknown)
|
||||
@ -145,7 +145,7 @@ def test_get_failed(web_client: WebClient, mocker: MockerFixture) -> None:
|
||||
|
||||
def test_get_failed_http_error(web_client: WebClient, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must suppress any exception happened during status getting
|
||||
must suppress HTTP exception happened during status getting
|
||||
"""
|
||||
mocker.patch("requests.Session.get", side_effect=requests.exceptions.HTTPError())
|
||||
assert web_client.get(None) == []
|
||||
@ -193,7 +193,7 @@ def test_get_internal_failed(web_client: WebClient, mocker: MockerFixture) -> No
|
||||
|
||||
def test_get_internal_failed_http_error(web_client: WebClient, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must suppress any exception happened during web service status getting
|
||||
must suppress HTTP exception happened during web service status getting
|
||||
"""
|
||||
mocker.patch("requests.Session.get", side_effect=requests.exceptions.HTTPError())
|
||||
assert web_client.get_internal() == InternalStatus()
|
||||
@ -224,7 +224,7 @@ def test_get_self_failed(web_client: WebClient, mocker: MockerFixture) -> None:
|
||||
|
||||
def test_get_self_failed_http_error(web_client: WebClient, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must suppress any exception happened during service status getting
|
||||
must suppress HTTP exception happened during service status getting
|
||||
"""
|
||||
mocker.patch("requests.Session.get", side_effect=requests.exceptions.HTTPError())
|
||||
assert web_client.get_self().status == BuildStatusEnum.Unknown
|
||||
@ -250,7 +250,7 @@ def test_remove_failed(web_client: WebClient, package_ahriman: Package, mocker:
|
||||
|
||||
def test_remove_failed_http_error(web_client: WebClient, package_ahriman: Package, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must suppress any exception happened during removal
|
||||
must suppress HTTP exception happened during removal
|
||||
"""
|
||||
mocker.patch("requests.Session.delete", side_effect=requests.exceptions.HTTPError())
|
||||
web_client.remove(package_ahriman.base)
|
||||
@ -277,7 +277,7 @@ def test_update_failed(web_client: WebClient, package_ahriman: Package, mocker:
|
||||
|
||||
def test_update_failed_http_error(web_client: WebClient, package_ahriman: Package, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must suppress any exception happened during update
|
||||
must suppress HTTP exception happened during update
|
||||
"""
|
||||
mocker.patch("requests.Session.post", side_effect=requests.exceptions.HTTPError())
|
||||
web_client.update(package_ahriman.base, BuildStatusEnum.Unknown)
|
||||
@ -304,7 +304,7 @@ def test_update_self_failed(web_client: WebClient, mocker: MockerFixture) -> Non
|
||||
|
||||
def test_update_self_failed_http_error(web_client: WebClient, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must suppress any exception happened during service update
|
||||
must suppress HTTP exception happened during service update
|
||||
"""
|
||||
mocker.patch("requests.Session.post", side_effect=requests.exceptions.HTTPError())
|
||||
web_client.update_self(BuildStatusEnum.Unknown)
|
||||
|
@ -231,7 +231,7 @@ def test_gettype_from_section_with_architecture(configuration: Configuration) ->
|
||||
|
||||
def test_gettype_from_section_no_section(configuration: Configuration) -> None:
|
||||
"""
|
||||
must extract type from section name with architecture
|
||||
must raise NoSectionError during type extraction from section name with architecture
|
||||
"""
|
||||
# technically rsync:x86_64 is valid section
|
||||
# but in current configuration it must be considered as missing section
|
||||
|
@ -9,8 +9,8 @@ from pytest_mock import MockerFixture
|
||||
from unittest.mock import MagicMock
|
||||
|
||||
from ahriman.core.exceptions import BuildFailed, InvalidOption, UnsafeRun
|
||||
from ahriman.core.util import check_output, check_user, exception_response_text, filter_json, package_like, \
|
||||
pretty_datetime, pretty_size, tmpdir, walk
|
||||
from ahriman.core.util import check_output, check_user, exception_response_text, filter_json, full_version, \
|
||||
package_like, pretty_datetime, pretty_size, tmpdir, walk
|
||||
from ahriman.models.package import Package
|
||||
from ahriman.models.repository_paths import RepositoryPaths
|
||||
|
||||
@ -177,6 +177,16 @@ def test_filter_json_empty_value(package_ahriman: Package) -> None:
|
||||
assert "base" not in filter_json(probe, probe.keys())
|
||||
|
||||
|
||||
def test_full_version() -> None:
|
||||
"""
|
||||
must construct full version
|
||||
"""
|
||||
assert full_version("1", "r2388.d30e3201", "1") == "1:r2388.d30e3201-1"
|
||||
assert full_version(None, "0.12.1", "1") == "0.12.1-1"
|
||||
assert full_version(0, "0.12.1", "1") == "0.12.1-1"
|
||||
assert full_version(1, "0.12.1", "1") == "1:0.12.1-1"
|
||||
|
||||
|
||||
def test_package_like(package_ahriman: Package) -> None:
|
||||
"""
|
||||
package_like must return true for archives
|
||||
@ -298,24 +308,27 @@ def test_walk(resource_path_root: Path) -> None:
|
||||
must traverse directory recursively
|
||||
"""
|
||||
expected = sorted([
|
||||
resource_path_root / "core/ahriman.ini",
|
||||
resource_path_root / "core/logging.ini",
|
||||
resource_path_root / "models/aur_error",
|
||||
resource_path_root / "models/big_file_checksum",
|
||||
resource_path_root / "models/empty_file_checksum",
|
||||
resource_path_root / "models/package_ahriman_aur",
|
||||
resource_path_root / "models/package_ahriman_srcinfo",
|
||||
resource_path_root / "models/package_tpacpi-bat-git_srcinfo",
|
||||
resource_path_root / "models/package_yay_srcinfo",
|
||||
resource_path_root / "web/templates/build-status/login-modal.jinja2",
|
||||
resource_path_root / "web/templates/build-status/package-actions-modals.jinja2",
|
||||
resource_path_root / "web/templates/build-status/package-actions-script.jinja2",
|
||||
resource_path_root / "web/templates/static/favicon.ico",
|
||||
resource_path_root / "web/templates/utils/bootstrap-scripts.jinja2",
|
||||
resource_path_root / "web/templates/utils/style.jinja2",
|
||||
resource_path_root / "web/templates/build-status.jinja2",
|
||||
resource_path_root / "web/templates/email-index.jinja2",
|
||||
resource_path_root / "web/templates/repo-index.jinja2",
|
||||
resource_path_root / "core" / "ahriman.ini",
|
||||
resource_path_root / "core" / "logging.ini",
|
||||
resource_path_root / "models" / "aur_error",
|
||||
resource_path_root / "models" / "big_file_checksum",
|
||||
resource_path_root / "models" / "empty_file_checksum",
|
||||
resource_path_root / "models" / "official_error",
|
||||
resource_path_root / "models" / "package_ahriman_aur",
|
||||
resource_path_root / "models" / "package_akonadi_aur",
|
||||
resource_path_root / "models" / "package_ahriman_srcinfo",
|
||||
resource_path_root / "models" / "package_gcc10_srcinfo",
|
||||
resource_path_root / "models" / "package_tpacpi-bat-git_srcinfo",
|
||||
resource_path_root / "models" / "package_yay_srcinfo",
|
||||
resource_path_root / "web" / "templates" / "build-status" / "login-modal.jinja2",
|
||||
resource_path_root / "web" / "templates" / "build-status" / "package-actions-modals.jinja2",
|
||||
resource_path_root / "web" / "templates" / "build-status" / "package-actions-script.jinja2",
|
||||
resource_path_root / "web" / "templates" / "static" / "favicon.ico",
|
||||
resource_path_root / "web" / "templates" / "utils" / "bootstrap-scripts.jinja2",
|
||||
resource_path_root / "web" / "templates" / "utils" / "style.jinja2",
|
||||
resource_path_root / "web" / "templates" / "build-status.jinja2",
|
||||
resource_path_root / "web" / "templates" / "email-index.jinja2",
|
||||
resource_path_root / "web" / "templates" / "repo-index.jinja2",
|
||||
])
|
||||
local_files = list(sorted(walk(resource_path_root)))
|
||||
assert local_files == expected
|
||||
|
@ -9,7 +9,7 @@ from typing import Any, Dict
|
||||
from ahriman.models.aur_package import AURPackage
|
||||
|
||||
|
||||
def _get_data(resource_path_root: Path) -> Dict[str, Any]:
|
||||
def _get_aur_data(resource_path_root: Path) -> Dict[str, Any]:
|
||||
"""
|
||||
load package description from resource file
|
||||
:param resource_path_root: path to resource root
|
||||
@ -19,11 +19,21 @@ def _get_data(resource_path_root: Path) -> Dict[str, Any]:
|
||||
return json.loads(response)["results"][0]
|
||||
|
||||
|
||||
def _get_official_data(resource_path_root: Path) -> Dict[str, Any]:
|
||||
"""
|
||||
load package description from resource file
|
||||
:param resource_path_root: path to resource root
|
||||
:return: json descriptor
|
||||
"""
|
||||
response = (resource_path_root / "models" / "package_akonadi_aur").read_text()
|
||||
return json.loads(response)["results"][0]
|
||||
|
||||
|
||||
def test_from_json(aur_package_ahriman: AURPackage, resource_path_root: Path) -> None:
|
||||
"""
|
||||
must load package from json
|
||||
"""
|
||||
model = _get_data(resource_path_root)
|
||||
model = _get_aur_data(resource_path_root)
|
||||
assert AURPackage.from_json(model) == aur_package_ahriman
|
||||
|
||||
|
||||
@ -35,11 +45,19 @@ def test_from_json_2(aur_package_ahriman: AURPackage, mocker: MockerFixture) ->
|
||||
assert AURPackage.from_json(asdict(aur_package_ahriman)) == aur_package_ahriman
|
||||
|
||||
|
||||
def test_from_repo(aur_package_akonadi: AURPackage, resource_path_root: Path) -> None:
|
||||
"""
|
||||
must load package from repository api json
|
||||
"""
|
||||
model = _get_official_data(resource_path_root)
|
||||
assert AURPackage.from_repo(model) == aur_package_akonadi
|
||||
|
||||
|
||||
def test_convert(aur_package_ahriman: AURPackage, resource_path_root: Path) -> None:
|
||||
"""
|
||||
must convert fields to snakecase and also apply converters
|
||||
"""
|
||||
model = _get_data(resource_path_root)
|
||||
model = _get_aur_data(resource_path_root)
|
||||
converted = AURPackage.convert(model)
|
||||
known_fields = [pair.name for pair in fields(AURPackage)]
|
||||
assert all(field in known_fields for field in converted)
|
||||
|
@ -19,7 +19,7 @@ def test_build_status_enum_badges_color() -> None:
|
||||
|
||||
def test_build_status_enum_bootstrap_color() -> None:
|
||||
"""
|
||||
status color must be one of shields.io supported
|
||||
status color must be one of bootstrap supported
|
||||
"""
|
||||
SUPPORTED_COLORS = [
|
||||
"primary", "secondary", "success", "danger", "warning", "info", "light", "dark"
|
||||
|
@ -101,7 +101,7 @@ def test_from_aur(package_ahriman: Package, aur_package_ahriman: AURPackage, moc
|
||||
"""
|
||||
must construct package from aur
|
||||
"""
|
||||
mocker.patch("ahriman.core.alpm.aur.AUR.info", return_value=aur_package_ahriman)
|
||||
mocker.patch("ahriman.core.alpm.remote.aur.AUR.info", return_value=aur_package_ahriman)
|
||||
|
||||
package = Package.from_aur(package_ahriman.base, package_ahriman.aur_url)
|
||||
assert package_ahriman.base == package.base
|
||||
@ -154,6 +154,18 @@ def test_from_json_view_3(package_tpacpi_bat_git: Package) -> None:
|
||||
assert Package.from_json(package_tpacpi_bat_git.view()) == package_tpacpi_bat_git
|
||||
|
||||
|
||||
def test_from_official(package_ahriman: Package, aur_package_ahriman: AURPackage, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must construct package from official repository
|
||||
"""
|
||||
mocker.patch("ahriman.core.alpm.remote.official.Official.info", return_value=aur_package_ahriman)
|
||||
|
||||
package = Package.from_official(package_ahriman.base, package_ahriman.aur_url)
|
||||
assert package_ahriman.base == package.base
|
||||
assert package_ahriman.version == package.version
|
||||
assert package_ahriman.packages.keys() == package.packages.keys()
|
||||
|
||||
|
||||
def test_load_resolve(package_ahriman: Package, pyalpm_handle: MagicMock, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must resolve source before package loading
|
||||
@ -193,6 +205,15 @@ def test_load_from_build(package_ahriman: Package, pyalpm_handle: MagicMock, moc
|
||||
load_mock.assert_called_once_with(Path("path"), package_ahriman.aur_url)
|
||||
|
||||
|
||||
def test_load_from_official(package_ahriman: Package, pyalpm_handle: MagicMock, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must load package from AUR
|
||||
"""
|
||||
load_mock = mocker.patch("ahriman.models.package.Package.from_official")
|
||||
Package.load("path", PackageSource.Repository, pyalpm_handle, package_ahriman.aur_url)
|
||||
load_mock.assert_called_once_with("path", package_ahriman.aur_url)
|
||||
|
||||
|
||||
def test_load_failure(package_ahriman: Package, pyalpm_handle: MagicMock, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must raise InvalidPackageInfo on exception
|
||||
@ -240,12 +261,14 @@ def test_dependencies_with_version(mocker: MockerFixture, resource_path_root: Pa
|
||||
assert Package.dependencies(Path("path")) == {"git", "go", "pacman"}
|
||||
|
||||
|
||||
def test_full_version() -> None:
|
||||
def test_dependencies_with_version_and_overlap(mocker: MockerFixture, resource_path_root: Path) -> None:
|
||||
"""
|
||||
must construct full version
|
||||
must load correct list of dependencies with version
|
||||
"""
|
||||
assert Package.full_version("1", "r2388.d30e3201", "1") == "1:r2388.d30e3201-1"
|
||||
assert Package.full_version(None, "0.12.1", "1") == "0.12.1-1"
|
||||
srcinfo = (resource_path_root / "models" / "package_gcc10_srcinfo").read_text()
|
||||
mocker.patch("pathlib.Path.read_text", return_value=srcinfo)
|
||||
|
||||
assert Package.dependencies(Path("path")) == {"glibc", "doxygen", "binutils", "git", "libmpc", "python", "zstd"}
|
||||
|
||||
|
||||
def test_actual_version(package_ahriman: Package, repository_paths: RepositoryPaths) -> None:
|
||||
@ -281,7 +304,7 @@ def test_actual_version_srcinfo_failed(package_tpacpi_bat_git: Package, reposito
|
||||
def test_actual_version_vcs_failed(package_tpacpi_bat_git: Package, repository_paths: RepositoryPaths,
|
||||
mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must return same version in case if exception occurred
|
||||
must return same version in case if there are errors during parse
|
||||
"""
|
||||
mocker.patch("pathlib.Path.read_text", return_value="")
|
||||
mocker.patch("ahriman.models.package.parse_srcinfo", return_value=({"packages": {}}, ["an error"]))
|
||||
@ -292,7 +315,7 @@ def test_actual_version_vcs_failed(package_tpacpi_bat_git: Package, repository_p
|
||||
|
||||
|
||||
def test_full_depends(package_ahriman: Package, package_python_schedule: Package, pyalpm_package_ahriman: MagicMock,
|
||||
pyalpm_handle: MagicMock, mocker: MockerFixture) -> None:
|
||||
pyalpm_handle: MagicMock) -> None:
|
||||
"""
|
||||
must extract all dependencies from the package
|
||||
"""
|
||||
|
@ -21,7 +21,7 @@ async def test_get(client: TestClient, aur_package_ahriman: AURPackage, mocker:
|
||||
"""
|
||||
must call get request correctly
|
||||
"""
|
||||
mocker.patch("ahriman.core.alpm.aur.AUR.multisearch", return_value=[aur_package_ahriman])
|
||||
mocker.patch("ahriman.core.alpm.remote.aur.AUR.multisearch", return_value=[aur_package_ahriman])
|
||||
response = await client.get("/service-api/v1/search", params={"for": "ahriman"})
|
||||
|
||||
assert response.ok
|
||||
@ -33,7 +33,7 @@ async def test_get_exception(client: TestClient, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must raise 400 on empty search string
|
||||
"""
|
||||
search_mock = mocker.patch("ahriman.core.alpm.aur.AUR.multisearch", return_value=[])
|
||||
search_mock = mocker.patch("ahriman.core.alpm.remote.aur.AUR.multisearch", return_value=[])
|
||||
response = await client.get("/service-api/v1/search")
|
||||
|
||||
assert response.status == 404
|
||||
@ -44,7 +44,7 @@ async def test_get_join(client: TestClient, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must join search args with space
|
||||
"""
|
||||
search_mock = mocker.patch("ahriman.core.alpm.aur.AUR.multisearch")
|
||||
search_mock = mocker.patch("ahriman.core.alpm.remote.aur.AUR.multisearch")
|
||||
response = await client.get("/service-api/v1/search", params=[("for", "ahriman"), ("for", "maybe")])
|
||||
|
||||
assert response.ok
|
||||
|
8
tests/testresources/models/official_error
Normal file
8
tests/testresources/models/official_error
Normal file
@ -0,0 +1,8 @@
|
||||
{
|
||||
"version": 2,
|
||||
"limit": 250,
|
||||
"valid": false,
|
||||
"results": [],
|
||||
"num_pages": 1,
|
||||
"page": 1
|
||||
}
|
55
tests/testresources/models/package_akonadi_aur
Normal file
55
tests/testresources/models/package_akonadi_aur
Normal file
@ -0,0 +1,55 @@
|
||||
{
|
||||
"version": 2,
|
||||
"limit": 250,
|
||||
"valid": true,
|
||||
"results": [
|
||||
{
|
||||
"pkgname": "akonadi",
|
||||
"pkgbase": "akonadi",
|
||||
"repo": "extra",
|
||||
"arch": "x86_64",
|
||||
"pkgver": "21.12.3",
|
||||
"pkgrel": "2",
|
||||
"epoch": 0,
|
||||
"pkgdesc": "PIM layer, which provides an asynchronous API to access all kind of PIM data",
|
||||
"url": "https://kontact.kde.org",
|
||||
"filename": "akonadi-21.12.3-2-x86_64.pkg.tar.zst",
|
||||
"compressed_size": 789510,
|
||||
"installed_size": 2592656,
|
||||
"build_date": "2022-03-04T11:50:03Z",
|
||||
"last_update": "2022-03-06T08:39:50.610Z",
|
||||
"flag_date": null,
|
||||
"maintainers": [
|
||||
"felixonmars",
|
||||
"arojas"
|
||||
],
|
||||
"packager": "arojas",
|
||||
"groups": [],
|
||||
"licenses": [
|
||||
"LGPL"
|
||||
],
|
||||
"conflicts": [],
|
||||
"provides": [],
|
||||
"replaces": [],
|
||||
"depends": [
|
||||
"libakonadi",
|
||||
"mariadb"
|
||||
],
|
||||
"optdepends": [
|
||||
"postgresql: PostgreSQL backend"
|
||||
],
|
||||
"makedepends": [
|
||||
"boost",
|
||||
"doxygen",
|
||||
"extra-cmake-modules",
|
||||
"kaccounts-integration",
|
||||
"kitemmodels",
|
||||
"postgresql",
|
||||
"qt5-tools"
|
||||
],
|
||||
"checkdepends": []
|
||||
}
|
||||
],
|
||||
"num_pages": 1,
|
||||
"page": 1
|
||||
}
|
57
tests/testresources/models/package_gcc10_srcinfo
Normal file
57
tests/testresources/models/package_gcc10_srcinfo
Normal file
@ -0,0 +1,57 @@
|
||||
pkgbase = gcc10
|
||||
pkgdesc = The GNU Compiler Collection (10.x.x)
|
||||
pkgver = 10.3.0
|
||||
pkgrel = 2
|
||||
url = https://gcc.gnu.org
|
||||
arch = x86_64
|
||||
license = GPL
|
||||
license = LGPL
|
||||
license = FDL
|
||||
license = custom
|
||||
checkdepends = dejagnu
|
||||
checkdepends = inetutils
|
||||
makedepends = binutils
|
||||
makedepends = doxygen
|
||||
makedepends = git
|
||||
makedepends = libmpc
|
||||
makedepends = python
|
||||
options = !emptydirs
|
||||
options = !lto
|
||||
source = https://sourceware.org/pub/gcc/releases/gcc-10.3.0/gcc-10.3.0.tar.xz
|
||||
source = https://sourceware.org/pub/gcc/releases/gcc-10.3.0/gcc-10.3.0.tar.xz.sig
|
||||
source = https://mirror.sobukus.de/files/src/isl/isl-0.24.tar.xz
|
||||
source = c89
|
||||
source = c99
|
||||
validpgpkeys = F3691687D867B81B51CE07D9BBE43771487328A9
|
||||
validpgpkeys = 86CFFCA918CF3AF47147588051E8B148A9999C34
|
||||
validpgpkeys = 13975A70E63C361C73AE69EF6EEB81F8981C74C7
|
||||
validpgpkeys = D3A93CAD751C2AF4F8C7AD516C35B99309B5FA62
|
||||
b2sums = ac7898f5eb8a7c5f151a526d1bb38913a68b50a65e4d010ac09fa20b6c801c671c790d780f23ccb8e4ecdfc686f4aa588082ccc9eb5c80c7b0e30788f824c1eb
|
||||
b2sums = SKIP
|
||||
b2sums = 39cbfd18ad05778e3a5a44429261b45e4abc3efe7730ee890674d968890fe5e52c73bc1f8d271c7c3bc72d5754e3f7fcb209bd139e823d19cb9ea4ce1440164d
|
||||
b2sums = a76d19c7830b0a141302890522086fc1548c177611501caac7e66d576e541b64ca3f6e977de715268a9872dfdd6368a011b92e01f7944ec0088f899ac0d2a2a5
|
||||
b2sums = 02b655b5668f7dea51c3b3e4ff46d5a4aee5a04ed5e26b98a6470f39c2e98ddc0519bffeeedd982c31ef3c171457e4d1beaff32767d1aedd9346837aac4ec3ee
|
||||
|
||||
pkgname = gcc10
|
||||
pkgdesc = The GNU Compiler Collection - C and C++ frontends (10.x.x)
|
||||
depends = gcc10-libs=10.3.0-2
|
||||
depends = binutils>=2.28
|
||||
depends = libmpc
|
||||
depends = zstd
|
||||
options = !emptydirs
|
||||
options = staticlibs
|
||||
|
||||
pkgname = gcc10-libs
|
||||
pkgdesc = Runtime libraries shipped by GCC (10.x.x)
|
||||
depends = glibc>=2.27
|
||||
provides = libgfortran.so
|
||||
provides = libubsan.so
|
||||
provides = libasan.so
|
||||
provides = libtsan.so
|
||||
provides = liblsan.so
|
||||
options = !emptydirs
|
||||
options = !strip
|
||||
|
||||
pkgname = gcc10-fortran
|
||||
pkgdesc = Fortran front-end for GCC (10.x.x)
|
||||
depends = gcc10=10.3.0-2
|
Reference in New Issue
Block a user