mirror of
https://github.com/arcan1s/ahriman.git
synced 2025-04-24 07:17:17 +00:00
Complete official repository support (#59)
This commit is contained in:
parent
5030395025
commit
571f720ae2
@ -22,7 +22,7 @@ This package contains application (aka executable) related classes and everythin
|
|||||||
|
|
||||||
This package contains everything which is required for any time of application run and separated to several packages:
|
This package contains everything which is required for any time of application run and separated to several packages:
|
||||||
|
|
||||||
* `ahriman.core.alpm` package controls pacman related functions. It provides wrappers for `pyalpm` library and safe calls for repository tools (`repo-add` and `repo-remove`).
|
* `ahriman.core.alpm` package controls pacman related functions. It provides wrappers for `pyalpm` library and safe calls for repository tools (`repo-add` and `repo-remove`). Also this package contains `ahriman.core.alpm.remote` package which provides wrapper for remote sources (e.g. AUR RPC and official repositories RPC).
|
||||||
* `ahriman.core.auth` package provides classes for authorization methods used by web mostly. Base class is `ahriman.core.auth.auth.Auth` which must be called by `load` method.
|
* `ahriman.core.auth` package provides classes for authorization methods used by web mostly. Base class is `ahriman.core.auth.auth.Auth` which must be called by `load` method.
|
||||||
* `ahriman.core.build_tools` is a package which provides wrapper for `devtools` commands.
|
* `ahriman.core.build_tools` is a package which provides wrapper for `devtools` commands.
|
||||||
* `ahriman.core.database` is everything including data and schema migrations for database.
|
* `ahriman.core.database` is everything including data and schema migrations for database.
|
||||||
|
@ -23,7 +23,6 @@ Base configuration settings.
|
|||||||
|
|
||||||
libalpm and AUR related configuration.
|
libalpm and AUR related configuration.
|
||||||
|
|
||||||
* `aur_url` - base url for AUR, string, required.
|
|
||||||
* `database` - path to pacman local database cache, string, required.
|
* `database` - path to pacman local database cache, string, required.
|
||||||
* `repositories` - list of pacman repositories, space separated list of strings, required.
|
* `repositories` - list of pacman repositories, space separated list of strings, required.
|
||||||
* `root` - root for alpm library, string, required.
|
* `root` - root for alpm library, string, required.
|
||||||
|
@ -113,6 +113,14 @@ Well it is supported also.
|
|||||||
|
|
||||||
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).
|
||||||
|
|
||||||
|
### Hey, I would like to rebuild the official repository package
|
||||||
|
|
||||||
|
So it is the same as adding any other package, but due to restrictions you must specify source explicitly, e.g.:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
sudo -u ahriman ahriman package-add pacmann -s repository
|
||||||
|
```
|
||||||
|
|
||||||
### Package build fails because it cannot validate PGP signature of source files
|
### Package build fails because it cannot validate PGP signature of source files
|
||||||
|
|
||||||
TL;DR
|
TL;DR
|
||||||
|
@ -4,7 +4,6 @@ logging = ahriman.ini.d/logging.ini
|
|||||||
database = /var/lib/ahriman/ahriman.db
|
database = /var/lib/ahriman/ahriman.db
|
||||||
|
|
||||||
[alpm]
|
[alpm]
|
||||||
aur_url = https://aur.archlinux.org
|
|
||||||
database = /var/lib/pacman
|
database = /var/lib/pacman
|
||||||
repositories = core extra community multilib
|
repositories = core extra community multilib
|
||||||
root = /
|
root = /
|
||||||
|
@ -74,7 +74,7 @@
|
|||||||
{% for package in packages %}
|
{% for package in packages %}
|
||||||
<tr data-package-base="{{ package.base }}">
|
<tr data-package-base="{{ package.base }}">
|
||||||
<td data-checkbox="true"></td>
|
<td data-checkbox="true"></td>
|
||||||
<td><a href="{{ package.web_url }}" title="{{ package.base }}">{{ package.base }}</a></td>
|
<td>{% if package.web_url is not none %}<a href="{{ package.web_url }}" title="{{ package.base }}">{{ package.base }}</a>{% else %}{{ package.base }}{% endif %}</td>
|
||||||
<td>{{ package.version }}</td>
|
<td>{{ package.version }}</td>
|
||||||
<td>{{ package.packages|join("<br>"|safe) }}</td>
|
<td>{{ package.packages|join("<br>"|safe) }}</td>
|
||||||
<td>{{ package.groups|join("<br>"|safe) }}</td>
|
<td>{{ package.groups|join("<br>"|safe) }}</td>
|
||||||
|
@ -80,12 +80,13 @@ class ApplicationPackages(ApplicationProperties):
|
|||||||
known_packages(Set[str]): list of packages which are known by the service
|
known_packages(Set[str]): list of packages which are known by the service
|
||||||
without_dependencies(bool): if set, dependency check will be disabled
|
without_dependencies(bool): if set, dependency check will be disabled
|
||||||
"""
|
"""
|
||||||
package = Package.load(source, PackageSource.AUR, self.repository.pacman, self.repository.aur_url)
|
package = Package.from_aur(source, self.repository.pacman)
|
||||||
|
|
||||||
self.database.build_queue_insert(package)
|
self.database.build_queue_insert(package)
|
||||||
|
self.database.remote_update(package)
|
||||||
|
|
||||||
with tmpdir() as local_path:
|
with tmpdir() as local_path:
|
||||||
Sources.load(local_path, package.git_url, self.database.patches_get(package.base))
|
Sources.load(local_path, package.remote, self.database.patches_get(package.base))
|
||||||
self._process_dependencies(local_path, known_packages, without_dependencies)
|
self._process_dependencies(local_path, known_packages, without_dependencies)
|
||||||
|
|
||||||
def _add_directory(self, source: str, *_: Any) -> None:
|
def _add_directory(self, source: str, *_: Any) -> None:
|
||||||
@ -108,9 +109,10 @@ class ApplicationPackages(ApplicationProperties):
|
|||||||
known_packages(Set[str]): list of packages which are known by the service
|
known_packages(Set[str]): list of packages which are known by the service
|
||||||
without_dependencies(bool): if set, dependency check will be disabled
|
without_dependencies(bool): if set, dependency check will be disabled
|
||||||
"""
|
"""
|
||||||
package = Package.load(source, PackageSource.Local, self.repository.pacman, self.repository.aur_url)
|
source_dir = Path(source)
|
||||||
|
package = Package.from_build(source_dir)
|
||||||
cache_dir = self.repository.paths.cache_for(package.base)
|
cache_dir = self.repository.paths.cache_for(package.base)
|
||||||
shutil.copytree(Path(source), cache_dir) # copy package to store in caches
|
shutil.copytree(source_dir, 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
|
Sources.init(cache_dir) # we need to run init command in directory where we do have permissions
|
||||||
|
|
||||||
self.database.build_queue_insert(package)
|
self.database.build_queue_insert(package)
|
||||||
@ -132,6 +134,18 @@ class ApplicationPackages(ApplicationProperties):
|
|||||||
for chunk in response.iter_content(chunk_size=1024):
|
for chunk in response.iter_content(chunk_size=1024):
|
||||||
local_file.write(chunk)
|
local_file.write(chunk)
|
||||||
|
|
||||||
|
def _add_repository(self, source: str, *_: Any) -> None:
|
||||||
|
"""
|
||||||
|
add package from official repository
|
||||||
|
|
||||||
|
Args:
|
||||||
|
source(str): package base name
|
||||||
|
"""
|
||||||
|
package = Package.from_official(source, self.repository.pacman)
|
||||||
|
self.database.build_queue_insert(package)
|
||||||
|
self.database.remote_update(package)
|
||||||
|
# repository packages must not depend on unknown packages, thus we are not going to process dependencies
|
||||||
|
|
||||||
def _process_dependencies(self, local_path: Path, known_packages: Set[str], without_dependencies: bool) -> None:
|
def _process_dependencies(self, local_path: Path, known_packages: Set[str], without_dependencies: bool) -> None:
|
||||||
"""
|
"""
|
||||||
process package dependencies
|
process package dependencies
|
||||||
|
@ -128,14 +128,14 @@ class ApplicationRepository(ApplicationProperties):
|
|||||||
packages: List[str] = []
|
packages: List[str] = []
|
||||||
for single in probe.packages:
|
for single in probe.packages:
|
||||||
try:
|
try:
|
||||||
_ = Package.from_aur(single, probe.aur_url)
|
_ = Package.from_aur(single, self.repository.pacman)
|
||||||
except Exception:
|
except Exception:
|
||||||
packages.append(single)
|
packages.append(single)
|
||||||
return packages
|
return packages
|
||||||
|
|
||||||
def unknown_local(probe: Package) -> List[str]:
|
def unknown_local(probe: Package) -> List[str]:
|
||||||
cache_dir = self.repository.paths.cache_for(probe.base)
|
cache_dir = self.repository.paths.cache_for(probe.base)
|
||||||
local = Package.from_build(cache_dir, probe.aur_url)
|
local = Package.from_build(cache_dir)
|
||||||
packages = set(probe.packages.keys()).difference(local.packages.keys())
|
packages = set(probe.packages.keys()).difference(local.packages.keys())
|
||||||
return list(packages)
|
return list(packages)
|
||||||
|
|
||||||
|
@ -29,7 +29,6 @@ from ahriman.core.configuration import Configuration
|
|||||||
from ahriman.core.formatters.string_printer import StringPrinter
|
from ahriman.core.formatters.string_printer import StringPrinter
|
||||||
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.package_source import PackageSource
|
|
||||||
|
|
||||||
|
|
||||||
class Patch(Handler):
|
class Patch(Handler):
|
||||||
@ -57,21 +56,20 @@ class Patch(Handler):
|
|||||||
elif args.action == Action.Remove:
|
elif args.action == Action.Remove:
|
||||||
Patch.patch_set_remove(application, args.package)
|
Patch.patch_set_remove(application, args.package)
|
||||||
elif args.action == Action.Update:
|
elif args.action == Action.Update:
|
||||||
Patch.patch_set_create(application, args.package, args.track)
|
Patch.patch_set_create(application, Path(args.package), args.track)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def patch_set_create(application: Application, sources_dir: str, track: List[str]) -> None:
|
def patch_set_create(application: Application, sources_dir: Path, track: List[str]) -> 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(str): path to directory with the package sources
|
sources_dir(Path): path to directory with the package sources
|
||||||
track(List[str]): track files which match the glob before creating the patch
|
track(List[str]): track files which match the glob before creating the patch
|
||||||
"""
|
"""
|
||||||
package = Package.load(sources_dir, PackageSource.Local, application.repository.pacman,
|
package = Package.from_build(sources_dir)
|
||||||
application.repository.aur_url)
|
patch = Sources.patch_create(sources_dir, *track)
|
||||||
patch = Sources.patch_create(Path(sources_dir), *track)
|
|
||||||
application.database.patches_insert(package.base, patch)
|
application.database.patches_insert(package.base, patch)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
|
@ -22,6 +22,7 @@ import argparse
|
|||||||
from dataclasses import fields
|
from dataclasses import fields
|
||||||
from typing import Callable, Iterable, List, Tuple, Type
|
from typing import Callable, Iterable, List, Tuple, Type
|
||||||
|
|
||||||
|
from ahriman.application.application import Application
|
||||||
from ahriman.application.handlers.handler import Handler
|
from ahriman.application.handlers.handler import Handler
|
||||||
from ahriman.core.alpm.remote.aur import AUR
|
from ahriman.core.alpm.remote.aur import AUR
|
||||||
from ahriman.core.alpm.remote.official import Official
|
from ahriman.core.alpm.remote.official import Official
|
||||||
@ -55,8 +56,10 @@ class Search(Handler):
|
|||||||
no_report(bool): force disable reporting
|
no_report(bool): force disable reporting
|
||||||
unsafe(bool): if set no user check will be performed before path creation
|
unsafe(bool): if set no user check will be performed before path creation
|
||||||
"""
|
"""
|
||||||
official_packages_list = Official.multisearch(*args.search)
|
application = Application(architecture, configuration, no_report, unsafe)
|
||||||
aur_packages_list = AUR.multisearch(*args.search)
|
|
||||||
|
official_packages_list = Official.multisearch(*args.search, pacman=application.repository.pacman)
|
||||||
|
aur_packages_list = AUR.multisearch(*args.search, pacman=application.repository.pacman)
|
||||||
Search.check_if_empty(args.exit_code, not official_packages_list and not aur_packages_list)
|
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):
|
for packages_list in (official_packages_list, aur_packages_list):
|
||||||
|
@ -17,8 +17,8 @@
|
|||||||
# 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 pyalpm import Handle # type: ignore
|
from pyalpm import Handle, Package, SIG_PACKAGE # type: ignore
|
||||||
from typing import Set
|
from typing import Generator, Set
|
||||||
|
|
||||||
from ahriman.core.configuration import Configuration
|
from ahriman.core.configuration import Configuration
|
||||||
|
|
||||||
@ -42,7 +42,7 @@ class Pacman:
|
|||||||
pacman_root = configuration.getpath("alpm", "database")
|
pacman_root = configuration.getpath("alpm", "database")
|
||||||
self.handle = Handle(root, str(pacman_root))
|
self.handle = Handle(root, str(pacman_root))
|
||||||
for repository in configuration.getlist("alpm", "repositories"):
|
for repository in configuration.getlist("alpm", "repositories"):
|
||||||
self.handle.register_syncdb(repository, 0) # 0 is pgp_level
|
self.handle.register_syncdb(repository, SIG_PACKAGE)
|
||||||
|
|
||||||
def all_packages(self) -> Set[str]:
|
def all_packages(self) -> Set[str]:
|
||||||
"""
|
"""
|
||||||
@ -58,3 +58,19 @@ class Pacman:
|
|||||||
result.update(package.provides) # provides list for meta-packages
|
result.update(package.provides) # provides list for meta-packages
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
def get(self, package_name: str) -> Generator[Package, None, None]:
|
||||||
|
"""
|
||||||
|
retrieve list of the packages from the repository by name
|
||||||
|
|
||||||
|
Args:
|
||||||
|
package_name(str): package name to search
|
||||||
|
|
||||||
|
Yields:
|
||||||
|
Package: list of packages which were returned by the query
|
||||||
|
"""
|
||||||
|
for database in self.handle.get_syncdbs():
|
||||||
|
package = database.get_pkg(package_name)
|
||||||
|
if package is None:
|
||||||
|
continue
|
||||||
|
yield package
|
||||||
|
@ -19,8 +19,9 @@
|
|||||||
#
|
#
|
||||||
import requests
|
import requests
|
||||||
|
|
||||||
from typing import Any, Dict, List, Optional
|
from typing import Any, Dict, List
|
||||||
|
|
||||||
|
from ahriman.core.alpm.pacman import Pacman
|
||||||
from ahriman.core.alpm.remote.remote import Remote
|
from ahriman.core.alpm.remote.remote import Remote
|
||||||
from ahriman.core.exceptions import InvalidPackageInfo
|
from ahriman.core.exceptions import InvalidPackageInfo
|
||||||
from ahriman.core.util import exception_response_text
|
from ahriman.core.util import exception_response_text
|
||||||
@ -32,27 +33,15 @@ class AUR(Remote):
|
|||||||
AUR RPC wrapper
|
AUR RPC wrapper
|
||||||
|
|
||||||
Attributes:
|
Attributes:
|
||||||
|
DEFAULT_AUR_URL(str): (class attribute) default AUR url
|
||||||
DEFAULT_RPC_URL(str): (class attribute) default AUR RPC url
|
DEFAULT_RPC_URL(str): (class attribute) default AUR RPC url
|
||||||
DEFAULT_RPC_VERSION(str): (class attribute) default AUR RPC version
|
DEFAULT_RPC_VERSION(str): (class attribute) default AUR RPC version
|
||||||
rpc_url(str): AUR RPC url
|
|
||||||
rpc_version(str): AUR RPC version
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
DEFAULT_RPC_URL = "https://aur.archlinux.org/rpc"
|
DEFAULT_AUR_URL = "https://aur.archlinux.org"
|
||||||
|
DEFAULT_RPC_URL = f"{DEFAULT_AUR_URL}/rpc"
|
||||||
DEFAULT_RPC_VERSION = "5"
|
DEFAULT_RPC_VERSION = "5"
|
||||||
|
|
||||||
def __init__(self, rpc_url: Optional[str] = None, rpc_version: Optional[str] = None) -> None:
|
|
||||||
"""
|
|
||||||
default constructor
|
|
||||||
|
|
||||||
Args:
|
|
||||||
rpc_url(Optional[str], optional): AUR RPC url (Default value = None)
|
|
||||||
rpc_version(Optional[str], optional): AUR RPC version (Default value = None)
|
|
||||||
"""
|
|
||||||
Remote.__init__(self)
|
|
||||||
self.rpc_url = rpc_url or self.DEFAULT_RPC_URL
|
|
||||||
self.rpc_version = rpc_version or self.DEFAULT_RPC_VERSION
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def parse_response(response: Dict[str, Any]) -> List[AURPackage]:
|
def parse_response(response: Dict[str, Any]) -> List[AURPackage]:
|
||||||
"""
|
"""
|
||||||
@ -73,6 +62,33 @@ class AUR(Remote):
|
|||||||
raise InvalidPackageInfo(error_details)
|
raise InvalidPackageInfo(error_details)
|
||||||
return [AURPackage.from_json(package) for package in response["results"]]
|
return [AURPackage.from_json(package) for package in response["results"]]
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def remote_git_url(package_base: str, repository: str) -> str:
|
||||||
|
"""
|
||||||
|
generate remote git url from the package base
|
||||||
|
|
||||||
|
Args
|
||||||
|
package_base(str): package base
|
||||||
|
repository(str): repository name
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
str: git url for the specific base
|
||||||
|
"""
|
||||||
|
return f"{AUR.DEFAULT_AUR_URL}/{package_base}.git"
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def remote_web_url(package_base: str) -> str:
|
||||||
|
"""
|
||||||
|
generate remote web url from the package base
|
||||||
|
|
||||||
|
Args
|
||||||
|
package_base(str): package base
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
str: web url for the specific base
|
||||||
|
"""
|
||||||
|
return f"{AUR.DEFAULT_AUR_URL}/packages/{package_base}"
|
||||||
|
|
||||||
def make_request(self, request_type: str, *args: str, **kwargs: str) -> List[AURPackage]:
|
def make_request(self, request_type: str, *args: str, **kwargs: str) -> List[AURPackage]:
|
||||||
"""
|
"""
|
||||||
perform request to AUR RPC
|
perform request to AUR RPC
|
||||||
@ -87,7 +103,7 @@ class AUR(Remote):
|
|||||||
"""
|
"""
|
||||||
query: Dict[str, Any] = {
|
query: Dict[str, Any] = {
|
||||||
"type": request_type,
|
"type": request_type,
|
||||||
"v": self.rpc_version
|
"v": self.DEFAULT_RPC_VERSION
|
||||||
}
|
}
|
||||||
|
|
||||||
arg_query = "arg[]" if len(args) > 1 else "arg"
|
arg_query = "arg[]" if len(args) > 1 else "arg"
|
||||||
@ -97,7 +113,7 @@ class AUR(Remote):
|
|||||||
query[key] = value
|
query[key] = value
|
||||||
|
|
||||||
try:
|
try:
|
||||||
response = requests.get(self.rpc_url, params=query)
|
response = requests.get(self.DEFAULT_RPC_URL, params=query)
|
||||||
response.raise_for_status()
|
response.raise_for_status()
|
||||||
return self.parse_response(response.json())
|
return self.parse_response(response.json())
|
||||||
except requests.HTTPError as e:
|
except requests.HTTPError as e:
|
||||||
@ -110,12 +126,13 @@ class AUR(Remote):
|
|||||||
self.logger.exception("could not perform request by using type %s", request_type)
|
self.logger.exception("could not perform request by using type %s", request_type)
|
||||||
raise
|
raise
|
||||||
|
|
||||||
def package_info(self, package_name: str) -> AURPackage:
|
def package_info(self, package_name: str, *, pacman: Pacman) -> AURPackage:
|
||||||
"""
|
"""
|
||||||
get package info by its name
|
get package info by its name
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
package_name(str): package name to search
|
package_name(str): package name to search
|
||||||
|
pacman(Pacman): alpm wrapper instance
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
AURPackage: package which match the package name
|
AURPackage: package which match the package name
|
||||||
@ -123,12 +140,13 @@ class AUR(Remote):
|
|||||||
packages = self.make_request("info", package_name)
|
packages = self.make_request("info", package_name)
|
||||||
return next(package for package in packages if package.name == package_name)
|
return next(package for package in packages if package.name == package_name)
|
||||||
|
|
||||||
def package_search(self, *keywords: str) -> List[AURPackage]:
|
def package_search(self, *keywords: str, pacman: Pacman) -> List[AURPackage]:
|
||||||
"""
|
"""
|
||||||
search package in AUR web
|
search package in AUR web
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
*keywords(str): keywords to search
|
*keywords(str): keywords to search
|
||||||
|
pacman(Pacman): alpm wrapper instance
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
List[AURPackage]: list of packages which match the criteria
|
List[AURPackage]: list of packages which match the criteria
|
||||||
|
@ -19,8 +19,9 @@
|
|||||||
#
|
#
|
||||||
import requests
|
import requests
|
||||||
|
|
||||||
from typing import Any, Dict, List, Optional
|
from typing import Any, Dict, List
|
||||||
|
|
||||||
|
from ahriman.core.alpm.pacman import Pacman
|
||||||
from ahriman.core.alpm.remote.remote import Remote
|
from ahriman.core.alpm.remote.remote import Remote
|
||||||
from ahriman.core.exceptions import InvalidPackageInfo
|
from ahriman.core.exceptions import InvalidPackageInfo
|
||||||
from ahriman.core.util import exception_response_text
|
from ahriman.core.util import exception_response_text
|
||||||
@ -32,22 +33,15 @@ class Official(Remote):
|
|||||||
official repository RPC wrapper
|
official repository RPC wrapper
|
||||||
|
|
||||||
Attributes:
|
Attributes:
|
||||||
DEFAULT_RPC_URL(str): (class attribute) default AUR RPC url
|
DEFAULT_ARCHLINUX_URL(str): (class attribute) default archlinux url
|
||||||
rpc_url(str): AUR RPC url
|
DEFAULT_SEARCH_REPOSITORIES(List[str]): (class attribute) default list of repositories to search
|
||||||
|
DEFAULT_RPC_URL(str): (class attribute) default archlinux repositories RPC url
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
DEFAULT_ARCHLINUX_URL = "https://archlinux.org"
|
||||||
|
DEFAULT_SEARCH_REPOSITORIES = ["Core", "Extra", "Multilib", "Community"]
|
||||||
DEFAULT_RPC_URL = "https://archlinux.org/packages/search/json"
|
DEFAULT_RPC_URL = "https://archlinux.org/packages/search/json"
|
||||||
|
|
||||||
def __init__(self, rpc_url: Optional[str] = None) -> None:
|
|
||||||
"""
|
|
||||||
default constructor
|
|
||||||
|
|
||||||
Args:
|
|
||||||
rpc_url(Optional[str], optional): AUR RPC url (Default value = None)
|
|
||||||
"""
|
|
||||||
Remote.__init__(self)
|
|
||||||
self.rpc_url = rpc_url or self.DEFAULT_RPC_URL
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def parse_response(response: Dict[str, Any]) -> List[AURPackage]:
|
def parse_response(response: Dict[str, Any]) -> List[AURPackage]:
|
||||||
"""
|
"""
|
||||||
@ -66,6 +60,35 @@ class Official(Remote):
|
|||||||
raise InvalidPackageInfo("API validation error")
|
raise InvalidPackageInfo("API validation error")
|
||||||
return [AURPackage.from_repo(package) for package in response["results"]]
|
return [AURPackage.from_repo(package) for package in response["results"]]
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def remote_git_url(package_base: str, repository: str) -> str:
|
||||||
|
"""
|
||||||
|
generate remote git url from the package base
|
||||||
|
|
||||||
|
Args
|
||||||
|
package_base(str): package base
|
||||||
|
repository(str): repository name
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
str: git url for the specific base
|
||||||
|
"""
|
||||||
|
if repository.lower() in ("core", "extra", "testing", "kde-unstable"):
|
||||||
|
return "https://github.com/archlinux/svntogit-packages.git" # hardcoded, ok
|
||||||
|
return "https://github.com/archlinux/svntogit-community.git"
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def remote_web_url(package_base: str) -> str:
|
||||||
|
"""
|
||||||
|
generate remote web url from the package base
|
||||||
|
|
||||||
|
Args
|
||||||
|
package_base(str): package base
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
str: web url for the specific base
|
||||||
|
"""
|
||||||
|
return f"{Official.DEFAULT_ARCHLINUX_URL}/packages/{package_base}"
|
||||||
|
|
||||||
def make_request(self, *args: str, by: str) -> List[AURPackage]:
|
def make_request(self, *args: str, by: str) -> List[AURPackage]:
|
||||||
"""
|
"""
|
||||||
perform request to official repositories RPC
|
perform request to official repositories RPC
|
||||||
@ -78,7 +101,7 @@ class Official(Remote):
|
|||||||
List[AURPackage]: response parsed to package list
|
List[AURPackage]: response parsed to package list
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
response = requests.get(self.rpc_url, params={by: args})
|
response = requests.get(self.DEFAULT_RPC_URL, params={by: args, "repo": self.DEFAULT_SEARCH_REPOSITORIES})
|
||||||
response.raise_for_status()
|
response.raise_for_status()
|
||||||
return self.parse_response(response.json())
|
return self.parse_response(response.json())
|
||||||
except requests.HTTPError as e:
|
except requests.HTTPError as e:
|
||||||
@ -88,12 +111,13 @@ class Official(Remote):
|
|||||||
self.logger.exception("could not perform request")
|
self.logger.exception("could not perform request")
|
||||||
raise
|
raise
|
||||||
|
|
||||||
def package_info(self, package_name: str) -> AURPackage:
|
def package_info(self, package_name: str, *, pacman: Pacman) -> AURPackage:
|
||||||
"""
|
"""
|
||||||
get package info by its name
|
get package info by its name
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
package_name(str): package name to search
|
package_name(str): package name to search
|
||||||
|
pacman(Pacman): alpm wrapper instance
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
AURPackage: package which match the package name
|
AURPackage: package which match the package name
|
||||||
@ -101,12 +125,13 @@ class Official(Remote):
|
|||||||
packages = self.make_request(package_name, by="name")
|
packages = self.make_request(package_name, by="name")
|
||||||
return next(package for package in packages if package.name == package_name)
|
return next(package for package in packages if package.name == package_name)
|
||||||
|
|
||||||
def package_search(self, *keywords: str) -> List[AURPackage]:
|
def package_search(self, *keywords: str, pacman: Pacman) -> List[AURPackage]:
|
||||||
"""
|
"""
|
||||||
search package in AUR web
|
search package in AUR web
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
*keywords(str): keywords to search
|
*keywords(str): keywords to search
|
||||||
|
pacman(Pacman): alpm wrapper instance
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
List[AURPackage]: list of packages which match the criteria
|
List[AURPackage]: list of packages which match the criteria
|
||||||
|
51
src/ahriman/core/alpm/remote/official_syncdb.py
Normal file
51
src/ahriman/core/alpm/remote/official_syncdb.py
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
#
|
||||||
|
# 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 ahriman.core.alpm.pacman import Pacman
|
||||||
|
from ahriman.core.alpm.remote.official import Official
|
||||||
|
from ahriman.models.aur_package import AURPackage
|
||||||
|
|
||||||
|
|
||||||
|
class OfficialSyncdb(Official):
|
||||||
|
"""
|
||||||
|
official repository wrapper based on synchronized databases.
|
||||||
|
|
||||||
|
Despite the fact that official repository provides an API for the interaction according to the comment in issue
|
||||||
|
https://github.com/arcan1s/ahriman/pull/59#issuecomment-1106412297 we might face rate limits while requesting
|
||||||
|
updates.
|
||||||
|
|
||||||
|
This approach also has limitations, because we don't require superuser rights (neither going to download database
|
||||||
|
separately), the database file might be outdated and must be handled manually (or kind of). This behaviour might be
|
||||||
|
changed in the future.
|
||||||
|
|
||||||
|
Still we leave search function based on the official repositories RPC.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def package_info(self, package_name: str, *, pacman: Pacman) -> AURPackage:
|
||||||
|
"""
|
||||||
|
get package info by its name
|
||||||
|
|
||||||
|
Args:
|
||||||
|
package_name(str): package name to search
|
||||||
|
pacman(Pacman): alpm wrapper instance
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
AURPackage: package which match the package name
|
||||||
|
"""
|
||||||
|
return next(AURPackage.from_pacman(package) for package in pacman.get(package_name))
|
@ -23,6 +23,7 @@ import logging
|
|||||||
|
|
||||||
from typing import Dict, List, Type
|
from typing import Dict, List, Type
|
||||||
|
|
||||||
|
from ahriman.core.alpm.pacman import Pacman
|
||||||
from ahriman.models.aur_package import AURPackage
|
from ahriman.models.aur_package import AURPackage
|
||||||
|
|
||||||
|
|
||||||
@ -41,26 +42,28 @@ class Remote:
|
|||||||
self.logger = logging.getLogger("build_details")
|
self.logger = logging.getLogger("build_details")
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def info(cls: Type[Remote], package_name: str) -> AURPackage:
|
def info(cls: Type[Remote], package_name: str, *, pacman: Pacman) -> AURPackage:
|
||||||
"""
|
"""
|
||||||
get package info by its name
|
get package info by its name
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
package_name(str): package name to search
|
package_name(str): package name to search
|
||||||
|
pacman(Pacman): alpm wrapper instance
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
AURPackage: package which match the package name
|
AURPackage: package which match the package name
|
||||||
"""
|
"""
|
||||||
return cls().package_info(package_name)
|
return cls().package_info(package_name, pacman=pacman)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def multisearch(cls: Type[Remote], *keywords: str) -> List[AURPackage]:
|
def multisearch(cls: Type[Remote], *keywords: str, pacman: Pacman) -> List[AURPackage]:
|
||||||
"""
|
"""
|
||||||
search in remote repository by using API with multiple words. This method is required in order to handle
|
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
|
https://bugs.archlinux.org/task/49133. In addition, short words will be dropped
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
*keywords(str): search terms, e.g. "ahriman", "is", "cool"
|
*keywords(str): search terms, e.g. "ahriman", "is", "cool"
|
||||||
|
pacman(Pacman): alpm wrapper instance
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
List[AURPackage]: list of packages each of them matches all search terms
|
List[AURPackage]: list of packages each of them matches all search terms
|
||||||
@ -68,7 +71,7 @@ class Remote:
|
|||||||
instance = cls()
|
instance = cls()
|
||||||
packages: Dict[str, AURPackage] = {}
|
packages: Dict[str, AURPackage] = {}
|
||||||
for term in filter(lambda word: len(word) > 3, keywords):
|
for term in filter(lambda word: len(word) > 3, keywords):
|
||||||
portion = instance.search(term)
|
portion = instance.search(term, pacman=pacman)
|
||||||
packages = {
|
packages = {
|
||||||
package.name: package # not mistake to group them by name
|
package.name: package # not mistake to group them by name
|
||||||
for package in portion
|
for package in portion
|
||||||
@ -76,25 +79,60 @@ class Remote:
|
|||||||
}
|
}
|
||||||
return list(packages.values())
|
return list(packages.values())
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def remote_git_url(package_base: str, repository: str) -> str:
|
||||||
|
"""
|
||||||
|
generate remote git url from the package base
|
||||||
|
|
||||||
|
Args
|
||||||
|
package_base(str): package base
|
||||||
|
repository(str): repository name
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
str: git url for the specific base
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
NotImplementedError: not implemented method
|
||||||
|
"""
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def remote_web_url(package_base: str) -> str:
|
||||||
|
"""
|
||||||
|
generate remote web url from the package base
|
||||||
|
|
||||||
|
Args
|
||||||
|
package_base(str): package base
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
str: web url for the specific base
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
NotImplementedError: not implemented method
|
||||||
|
"""
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def search(cls: Type[Remote], *keywords: str) -> List[AURPackage]:
|
def search(cls: Type[Remote], *keywords: str, pacman: Pacman) -> List[AURPackage]:
|
||||||
"""
|
"""
|
||||||
search package in AUR web
|
search package in AUR web
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
*keywords(str): search terms, e.g. "ahriman", "is", "cool"
|
*keywords(str): search terms, e.g. "ahriman", "is", "cool"
|
||||||
|
pacman(Pacman): alpm wrapper instance
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
List[AURPackage]: list of packages which match the criteria
|
List[AURPackage]: list of packages which match the criteria
|
||||||
"""
|
"""
|
||||||
return cls().package_search(*keywords)
|
return cls().package_search(*keywords, pacman=pacman)
|
||||||
|
|
||||||
def package_info(self, package_name: str) -> AURPackage:
|
def package_info(self, package_name: str, *, pacman: Pacman) -> AURPackage:
|
||||||
"""
|
"""
|
||||||
get package info by its name
|
get package info by its name
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
package_name(str): package name to search
|
package_name(str): package name to search
|
||||||
|
pacman(Pacman): alpm wrapper instance
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
AURPackage: package which match the package name
|
AURPackage: package which match the package name
|
||||||
@ -104,12 +142,13 @@ class Remote:
|
|||||||
"""
|
"""
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
def package_search(self, *keywords: str) -> List[AURPackage]:
|
def package_search(self, *keywords: str, pacman: Pacman) -> List[AURPackage]:
|
||||||
"""
|
"""
|
||||||
search package in AUR web
|
search package in AUR web
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
*keywords(str): keywords to search
|
*keywords(str): keywords to search
|
||||||
|
pacman(Pacman): alpm wrapper instance
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
List[AURPackage]: list of packages which match the criteria
|
List[AURPackage]: list of packages which match the criteria
|
||||||
|
@ -18,11 +18,13 @@
|
|||||||
# 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 logging
|
import logging
|
||||||
|
import shutil
|
||||||
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import List, Optional
|
from typing import List, Optional
|
||||||
|
|
||||||
from ahriman.core.util import check_output
|
from ahriman.core.util import check_output, walk
|
||||||
|
from ahriman.models.remote_source import RemoteSource
|
||||||
|
|
||||||
|
|
||||||
class Sources:
|
class Sources:
|
||||||
@ -30,12 +32,14 @@ class Sources:
|
|||||||
helper to download package sources (PKGBUILD etc)
|
helper to download package sources (PKGBUILD etc)
|
||||||
|
|
||||||
Attributes:
|
Attributes:
|
||||||
|
DEFAULT_BRANCH(str): (class attribute) default branch to process git repositories.
|
||||||
|
Must be used only for local stored repositories, use RemoteSource descriptor instead for real packages
|
||||||
logger(logging.Logger): (class attribute) class logger
|
logger(logging.Logger): (class attribute) class logger
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
DEFAULT_BRANCH = "master" # default fallback branch
|
||||||
logger = logging.getLogger("build_details")
|
logger = logging.getLogger("build_details")
|
||||||
|
|
||||||
_branch = "master" # in case if BLM would like to change it
|
|
||||||
_check_output = check_output
|
_check_output = check_output
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
@ -73,13 +77,13 @@ class Sources:
|
|||||||
return Sources._check_output("git", "diff", exception=None, cwd=sources_dir, logger=Sources.logger)
|
return Sources._check_output("git", "diff", exception=None, cwd=sources_dir, logger=Sources.logger)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def fetch(sources_dir: Path, remote: Optional[str]) -> None:
|
def fetch(sources_dir: Path, remote: Optional[RemoteSource]) -> None:
|
||||||
"""
|
"""
|
||||||
either clone repository or update it to origin/`branch`
|
either clone repository or update it to origin/`branch`
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
sources_dir(Path): local path to fetch
|
sources_dir(Path): local path to fetch
|
||||||
remote(Optional[str]): remote target (from where to fetch)
|
remote(Optional[RemoteSource]): remote target (from where to fetch)
|
||||||
"""
|
"""
|
||||||
# local directory exists and there is .git directory
|
# local directory exists and there is .git directory
|
||||||
is_initialized_git = (sources_dir / ".git").is_dir()
|
is_initialized_git = (sources_dir / ".git").is_dir()
|
||||||
@ -88,22 +92,30 @@ class Sources:
|
|||||||
Sources.logger.info("skip update at %s because there are no branches configured", sources_dir)
|
Sources.logger.info("skip update at %s because there are no branches configured", sources_dir)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
branch = remote.branch if remote is not None else Sources.DEFAULT_BRANCH
|
||||||
if is_initialized_git:
|
if is_initialized_git:
|
||||||
Sources.logger.info("update HEAD to remote at %s", sources_dir)
|
Sources.logger.info("update HEAD to remote at %s using branch %s", sources_dir, branch)
|
||||||
Sources._check_output("git", "fetch", "origin", Sources._branch,
|
Sources._check_output("git", "fetch", "origin", branch,
|
||||||
|
exception=None, cwd=sources_dir, logger=Sources.logger)
|
||||||
|
elif remote is not None:
|
||||||
|
Sources.logger.info("clone remote %s to %s using branch %s", remote.git_url, sources_dir, branch)
|
||||||
|
Sources._check_output("git", "clone", "--branch", branch, "--single-branch",
|
||||||
|
remote.git_url, str(sources_dir),
|
||||||
exception=None, cwd=sources_dir, logger=Sources.logger)
|
exception=None, cwd=sources_dir, logger=Sources.logger)
|
||||||
elif remote is None:
|
|
||||||
Sources.logger.warning("%s is not initialized, but no remote provided", sources_dir)
|
|
||||||
else:
|
else:
|
||||||
Sources.logger.info("clone remote %s to %s", remote, sources_dir)
|
Sources.logger.warning("%s is not initialized, but no remote provided", sources_dir)
|
||||||
Sources._check_output("git", "clone", remote, str(sources_dir),
|
|
||||||
exception=None, cwd=sources_dir, logger=Sources.logger)
|
|
||||||
# and now force reset to our branch
|
# and now force reset to our branch
|
||||||
Sources._check_output("git", "checkout", "--force", Sources._branch,
|
Sources._check_output("git", "checkout", "--force", branch,
|
||||||
exception=None, cwd=sources_dir, logger=Sources.logger)
|
exception=None, cwd=sources_dir, logger=Sources.logger)
|
||||||
Sources._check_output("git", "reset", "--hard", f"origin/{Sources._branch}",
|
Sources._check_output("git", "reset", "--hard", f"origin/{branch}",
|
||||||
exception=None, cwd=sources_dir, logger=Sources.logger)
|
exception=None, cwd=sources_dir, logger=Sources.logger)
|
||||||
|
|
||||||
|
# move content if required
|
||||||
|
# we are using full path to source directory in order to make append possible
|
||||||
|
pkgbuild_dir = remote.pkgbuild_dir if remote is not None else sources_dir.resolve()
|
||||||
|
Sources.move((sources_dir / pkgbuild_dir).resolve(), sources_dir)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def has_remotes(sources_dir: Path) -> bool:
|
def has_remotes(sources_dir: Path) -> bool:
|
||||||
"""
|
"""
|
||||||
@ -126,17 +138,17 @@ class Sources:
|
|||||||
Args:
|
Args:
|
||||||
sources_dir(Path): local path to sources
|
sources_dir(Path): local path to sources
|
||||||
"""
|
"""
|
||||||
Sources._check_output("git", "init", "--initial-branch", Sources._branch,
|
Sources._check_output("git", "init", "--initial-branch", Sources.DEFAULT_BRANCH,
|
||||||
exception=None, cwd=sources_dir, logger=Sources.logger)
|
exception=None, cwd=sources_dir, logger=Sources.logger)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def load(sources_dir: Path, remote: str, patch: Optional[str]) -> None:
|
def load(sources_dir: Path, remote: Optional[RemoteSource], patch: Optional[str]) -> 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
|
||||||
remote(str): remote target (from where to fetch)
|
remote(Optional[RemoteSource]): remote target (from where to fetch)
|
||||||
patch(Optional[str]): optional patch to be applied
|
patch(Optional[str]): optional patch to be applied
|
||||||
"""
|
"""
|
||||||
Sources.fetch(sources_dir, remote)
|
Sources.fetch(sources_dir, remote)
|
||||||
@ -145,6 +157,21 @@ class Sources:
|
|||||||
return
|
return
|
||||||
Sources.patch_apply(sources_dir, patch)
|
Sources.patch_apply(sources_dir, patch)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def move(pkgbuild_dir: Path, sources_dir: Path) -> None:
|
||||||
|
"""
|
||||||
|
move content from pkgbuild_dir to sources_dir
|
||||||
|
|
||||||
|
Args:
|
||||||
|
pkgbuild_dir(Path): path to directory with pkgbuild from which need to move
|
||||||
|
sources_dir(Path): path to target directory
|
||||||
|
"""
|
||||||
|
if pkgbuild_dir == sources_dir:
|
||||||
|
return # directories are the same, no need to move
|
||||||
|
for src in walk(pkgbuild_dir):
|
||||||
|
dst = sources_dir / src.relative_to(pkgbuild_dir)
|
||||||
|
shutil.move(src, dst)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def patch_apply(sources_dir: Path, patch: str) -> None:
|
def patch_apply(sources_dir: Path, patch: str) -> None:
|
||||||
"""
|
"""
|
||||||
|
@ -107,4 +107,4 @@ class Task:
|
|||||||
if self.paths.cache_for(self.package.base).is_dir():
|
if self.paths.cache_for(self.package.base).is_dir():
|
||||||
# no need to clone whole repository, just copy from cache first
|
# no need to clone whole repository, just copy from cache first
|
||||||
shutil.copytree(self.paths.cache_for(self.package.base), path, dirs_exist_ok=True)
|
shutil.copytree(self.paths.cache_for(self.package.base), path, dirs_exist_ok=True)
|
||||||
Sources.load(path, self.package.git_url, database.patches_get(self.package.base))
|
Sources.load(path, self.package.remote, database.patches_get(self.package.base))
|
||||||
|
@ -20,6 +20,7 @@
|
|||||||
from sqlite3 import Connection
|
from sqlite3 import Connection
|
||||||
|
|
||||||
from ahriman.core.configuration import Configuration
|
from ahriman.core.configuration import Configuration
|
||||||
|
from ahriman.core.database.data.package_remotes import migrate_package_remotes
|
||||||
from ahriman.core.database.data.package_statuses import migrate_package_statuses
|
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.patches import migrate_patches
|
||||||
from ahriman.core.database.data.users import migrate_users_data
|
from ahriman.core.database.data.users import migrate_users_data
|
||||||
@ -43,3 +44,5 @@ def migrate_data(
|
|||||||
migrate_package_statuses(connection, repository_paths)
|
migrate_package_statuses(connection, repository_paths)
|
||||||
migrate_patches(connection, repository_paths)
|
migrate_patches(connection, repository_paths)
|
||||||
migrate_users_data(connection, configuration)
|
migrate_users_data(connection, configuration)
|
||||||
|
if result.old_version <= 1:
|
||||||
|
migrate_package_remotes(connection, repository_paths)
|
||||||
|
61
src/ahriman/core/database/data/package_remotes.py
Normal file
61
src/ahriman/core/database/data/package_remotes.py
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
#
|
||||||
|
# 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 sqlite3 import Connection
|
||||||
|
|
||||||
|
from ahriman.models.package_source import PackageSource
|
||||||
|
from ahriman.models.remote_source import RemoteSource
|
||||||
|
from ahriman.models.repository_paths import RepositoryPaths
|
||||||
|
|
||||||
|
|
||||||
|
# pylint: disable=protected-access
|
||||||
|
def migrate_package_remotes(connection: Connection, paths: RepositoryPaths) -> None:
|
||||||
|
"""
|
||||||
|
perform migration for package remote sources
|
||||||
|
|
||||||
|
Args:
|
||||||
|
connection(Connection): database connection
|
||||||
|
paths(RepositoryPaths): repository paths instance
|
||||||
|
"""
|
||||||
|
from ahriman.core.database.operations.package_operations import PackageOperations
|
||||||
|
|
||||||
|
def insert_remote(base: str, remote: RemoteSource) -> None:
|
||||||
|
connection.execute(
|
||||||
|
"""
|
||||||
|
update package_bases set
|
||||||
|
branch = :branch, git_url = :git_url, path = :path,
|
||||||
|
web_url = :web_url, source = :source
|
||||||
|
where package_base = :package_base
|
||||||
|
""",
|
||||||
|
dict(
|
||||||
|
package_base=base,
|
||||||
|
branch=remote.branch, git_url=remote.git_url, path=remote.path,
|
||||||
|
web_url=remote.web_url, source=remote.source
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
packages = PackageOperations._packages_get_select_package_bases(connection)
|
||||||
|
for package_base, package in packages.items():
|
||||||
|
local_cache = paths.cache_for(package_base)
|
||||||
|
if local_cache.exists() and not package.is_vcs:
|
||||||
|
continue # skip packages which are not VCS and with local cache
|
||||||
|
remote_source = RemoteSource.from_remote(PackageSource.AUR, package_base, "aur")
|
||||||
|
if remote_source is None:
|
||||||
|
continue # should never happen
|
||||||
|
insert_remote(package_base, remote_source)
|
@ -42,7 +42,7 @@ def migrate_package_statuses(connection: Connection, paths: RepositoryPaths) ->
|
|||||||
values
|
values
|
||||||
(:package_base, :version, :aur_url)
|
(:package_base, :version, :aur_url)
|
||||||
""",
|
""",
|
||||||
dict(package_base=metadata.base, version=metadata.version, aur_url=metadata.aur_url))
|
dict(package_base=metadata.base, version=metadata.version, aur_url=""))
|
||||||
connection.execute(
|
connection.execute(
|
||||||
"""
|
"""
|
||||||
insert into package_statuses
|
insert into package_statuses
|
||||||
|
40
src/ahriman/core/database/migrations/m001_package_source.py
Normal file
40
src/ahriman/core/database/migrations/m001_package_source.py
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
#
|
||||||
|
# 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/>.
|
||||||
|
#
|
||||||
|
|
||||||
|
steps = [
|
||||||
|
"""
|
||||||
|
alter table package_bases add column branch text
|
||||||
|
""",
|
||||||
|
"""
|
||||||
|
alter table package_bases add column git_url text
|
||||||
|
""",
|
||||||
|
"""
|
||||||
|
alter table package_bases add column path text
|
||||||
|
""",
|
||||||
|
"""
|
||||||
|
alter table package_bases add column web_url text
|
||||||
|
""",
|
||||||
|
"""
|
||||||
|
alter table package_bases add column source text
|
||||||
|
""",
|
||||||
|
"""
|
||||||
|
alter table package_bases drop column aur_url
|
||||||
|
""",
|
||||||
|
]
|
@ -24,6 +24,7 @@ from ahriman.core.database.operations.operations import Operations
|
|||||||
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.package_description import PackageDescription
|
from ahriman.models.package_description import PackageDescription
|
||||||
|
from ahriman.models.remote_source import RemoteSource
|
||||||
|
|
||||||
|
|
||||||
class PackageOperations(Operations):
|
class PackageOperations(Operations):
|
||||||
@ -75,13 +76,22 @@ class PackageOperations(Operations):
|
|||||||
connection.execute(
|
connection.execute(
|
||||||
"""
|
"""
|
||||||
insert into package_bases
|
insert into package_bases
|
||||||
(package_base, version, aur_url)
|
(package_base, version, source, branch, git_url, path, web_url)
|
||||||
values
|
values
|
||||||
(:package_base, :version, :aur_url)
|
(:package_base, :version, :source, :branch, :git_url, :path, :web_url)
|
||||||
on conflict (package_base) do update set
|
on conflict (package_base) do update set
|
||||||
version = :version, aur_url = :aur_url
|
version = :version, branch = :branch, git_url = :git_url, path = :path, web_url = :web_url, source = :source
|
||||||
""",
|
""",
|
||||||
dict(package_base=package.base, version=package.version, aur_url=package.aur_url))
|
dict(
|
||||||
|
package_base=package.base,
|
||||||
|
version=package.version,
|
||||||
|
branch=package.remote.branch if package.remote is not None else None,
|
||||||
|
git_url=package.remote.git_url if package.remote is not None else None,
|
||||||
|
path=package.remote.path if package.remote is not None else None,
|
||||||
|
web_url=package.remote.web_url if package.remote is not None else None,
|
||||||
|
source=package.remote.source.value if package.remote is not None else None,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _package_update_insert_packages(connection: Connection, package: Package) -> None:
|
def _package_update_insert_packages(connection: Connection, package: Package) -> None:
|
||||||
@ -144,7 +154,7 @@ class PackageOperations(Operations):
|
|||||||
Dict[str, Package]: map of the package base to its descriptor (without packages themselves)
|
Dict[str, Package]: map of the package base to its descriptor (without packages themselves)
|
||||||
"""
|
"""
|
||||||
return {
|
return {
|
||||||
row["package_base"]: Package(row["package_base"], row["version"], row["aur_url"], {})
|
row["package_base"]: Package(row["package_base"], row["version"], RemoteSource.from_json(row), {})
|
||||||
for row in connection.execute("""select * from package_bases""")
|
for row in connection.execute("""select * from package_bases""")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -225,3 +235,28 @@ class PackageOperations(Operations):
|
|||||||
yield package, statuses.get(package_base, BuildStatus())
|
yield package, statuses.get(package_base, BuildStatus())
|
||||||
|
|
||||||
return self.with_connection(lambda connection: list(run(connection)))
|
return self.with_connection(lambda connection: list(run(connection)))
|
||||||
|
|
||||||
|
def remote_update(self, package: Package) -> None:
|
||||||
|
"""
|
||||||
|
update package remote source
|
||||||
|
|
||||||
|
Args:
|
||||||
|
package(Package): package properties
|
||||||
|
"""
|
||||||
|
return self.with_connection(
|
||||||
|
lambda connection: self._package_update_insert_base(connection, package),
|
||||||
|
commit=True)
|
||||||
|
|
||||||
|
def remotes_get(self) -> Dict[str, RemoteSource]:
|
||||||
|
"""
|
||||||
|
get packages remotes based on current settings
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Dict[str, RemoteSource]: map of package base to its remote sources
|
||||||
|
"""
|
||||||
|
packages = self.with_connection(self._packages_get_select_package_bases)
|
||||||
|
return {
|
||||||
|
package_base: package.remote
|
||||||
|
for package_base, package in packages.items()
|
||||||
|
if package.remote is not None
|
||||||
|
}
|
||||||
|
@ -81,5 +81,5 @@ class SQLite(AuthOperations, BuildOperations, PackageOperations, PatchOperations
|
|||||||
|
|
||||||
paths = configuration.repository_paths
|
paths = configuration.repository_paths
|
||||||
|
|
||||||
self.with_connection(lambda conn: Migrations.migrate(conn, configuration))
|
self.with_connection(lambda connection: Migrations.migrate(connection, configuration))
|
||||||
paths.chown(self.path)
|
paths.chown(self.path)
|
||||||
|
@ -24,7 +24,6 @@ from ahriman.core.repository.executor import Executor
|
|||||||
from ahriman.core.repository.update_handler import UpdateHandler
|
from ahriman.core.repository.update_handler import UpdateHandler
|
||||||
from ahriman.core.util import package_like
|
from ahriman.core.util import package_like
|
||||||
from ahriman.models.package import Package
|
from ahriman.models.package import Package
|
||||||
from ahriman.models.package_source import PackageSource
|
|
||||||
|
|
||||||
|
|
||||||
class Repository(Executor, UpdateHandler):
|
class Repository(Executor, UpdateHandler):
|
||||||
@ -42,11 +41,15 @@ class Repository(Executor, UpdateHandler):
|
|||||||
Returns:
|
Returns:
|
||||||
List[Package]: list of read packages
|
List[Package]: list of read packages
|
||||||
"""
|
"""
|
||||||
|
sources = self.database.remotes_get()
|
||||||
|
|
||||||
result: Dict[str, Package] = {}
|
result: Dict[str, Package] = {}
|
||||||
# we are iterating over bases, not single packages
|
# we are iterating over bases, not single packages
|
||||||
for full_path in packages:
|
for full_path in packages:
|
||||||
try:
|
try:
|
||||||
local = Package.load(str(full_path), PackageSource.Archive, self.pacman, self.aur_url)
|
local = Package.from_archive(full_path, self.pacman, None)
|
||||||
|
local.remote = sources.get(local.base)
|
||||||
|
|
||||||
current = result.setdefault(local.base, local)
|
current = result.setdefault(local.base, local)
|
||||||
if current.version != local.version:
|
if current.version != local.version:
|
||||||
# force version to max of them
|
# force version to max of them
|
||||||
@ -95,5 +98,5 @@ class Repository(Executor, UpdateHandler):
|
|||||||
return [
|
return [
|
||||||
package
|
package
|
||||||
for package in packages
|
for package in packages
|
||||||
if depends_on is None or depends_on.intersection(package.full_depends(self.pacman, packages))
|
if depends_on.intersection(package.full_depends(self.pacman, packages))
|
||||||
]
|
]
|
||||||
|
@ -35,7 +35,6 @@ class RepositoryProperties:
|
|||||||
|
|
||||||
Attributes:
|
Attributes:
|
||||||
architecture(str): repository architecture
|
architecture(str): repository architecture
|
||||||
aur_url(str): base AUR url
|
|
||||||
configuration(Configuration): configuration instance
|
configuration(Configuration): configuration instance
|
||||||
database(SQLite): database instance
|
database(SQLite): database instance
|
||||||
ignore_list(List[str]): package bases which will be ignored during auto updates
|
ignore_list(List[str]): package bases which will be ignored during auto updates
|
||||||
@ -65,7 +64,6 @@ class RepositoryProperties:
|
|||||||
self.configuration = configuration
|
self.configuration = configuration
|
||||||
self.database = database
|
self.database = database
|
||||||
|
|
||||||
self.aur_url = configuration.get("alpm", "aur_url")
|
|
||||||
self.name = configuration.get("repository", "name")
|
self.name = configuration.get("repository", "name")
|
||||||
|
|
||||||
self.paths = configuration.repository_paths
|
self.paths = configuration.repository_paths
|
||||||
|
@ -62,12 +62,17 @@ class UpdateHandler(Cleaner):
|
|||||||
continue
|
continue
|
||||||
if filter_packages and local.base not in filter_packages:
|
if filter_packages and local.base not in filter_packages:
|
||||||
continue
|
continue
|
||||||
|
source = local.remote.source if local.remote is not None else None
|
||||||
|
|
||||||
try:
|
try:
|
||||||
remote = Package.load(local.base, PackageSource.AUR, self.pacman, self.aur_url)
|
if source == PackageSource.Repository:
|
||||||
|
remote = Package.from_official(local.base, self.pacman)
|
||||||
|
else:
|
||||||
|
remote = Package.from_aur(local.base, self.pacman)
|
||||||
if local.is_outdated(remote, self.paths):
|
if local.is_outdated(remote, self.paths):
|
||||||
self.reporter.set_pending(local.base)
|
self.reporter.set_pending(local.base)
|
||||||
result.append(remote)
|
result.append(remote)
|
||||||
|
else:
|
||||||
self.reporter.set_success(local)
|
self.reporter.set_success(local)
|
||||||
except Exception:
|
except Exception:
|
||||||
self.reporter.set_failed(local.base)
|
self.reporter.set_failed(local.base)
|
||||||
@ -89,7 +94,7 @@ class UpdateHandler(Cleaner):
|
|||||||
for dirname in self.paths.cache.iterdir():
|
for dirname in self.paths.cache.iterdir():
|
||||||
try:
|
try:
|
||||||
Sources.fetch(dirname, remote=None)
|
Sources.fetch(dirname, remote=None)
|
||||||
remote = Package.load(str(dirname), PackageSource.Local, self.pacman, self.aur_url)
|
remote = Package.from_build(dirname)
|
||||||
|
|
||||||
local = packages.get(remote.base)
|
local = packages.get(remote.base)
|
||||||
if local is None:
|
if local is None:
|
||||||
|
@ -70,7 +70,7 @@ class Leaf:
|
|||||||
Leaf: loaded class
|
Leaf: loaded class
|
||||||
"""
|
"""
|
||||||
with tmpdir() as clone_dir:
|
with tmpdir() as clone_dir:
|
||||||
Sources.load(clone_dir, package.git_url, database.patches_get(package.base))
|
Sources.load(clone_dir, package.remote, database.patches_get(package.base))
|
||||||
dependencies = Package.dependencies(clone_dir)
|
dependencies = Package.dependencies(clone_dir)
|
||||||
return cls(package, dependencies)
|
return cls(package, dependencies)
|
||||||
|
|
||||||
|
@ -20,7 +20,7 @@
|
|||||||
from enum import Enum
|
from enum import Enum
|
||||||
|
|
||||||
|
|
||||||
class Action(Enum):
|
class Action(str, Enum):
|
||||||
"""
|
"""
|
||||||
base action enumeration
|
base action enumeration
|
||||||
|
|
||||||
|
@ -23,6 +23,7 @@ import datetime
|
|||||||
import inflection
|
import inflection
|
||||||
|
|
||||||
from dataclasses import dataclass, field, fields
|
from dataclasses import dataclass, field, fields
|
||||||
|
from pyalpm import Package # type: ignore
|
||||||
from typing import Any, Callable, Dict, List, Optional, Type
|
from typing import Any, Callable, Dict, List, Optional, Type
|
||||||
|
|
||||||
from ahriman.core.util import filter_json, full_version
|
from ahriman.core.util import filter_json, full_version
|
||||||
@ -47,6 +48,7 @@ class AURPackage:
|
|||||||
first_submitted(datetime.datetime): timestamp of the first package submission
|
first_submitted(datetime.datetime): timestamp of the first package submission
|
||||||
last_modified(datetime.datetime): timestamp of the last package submission
|
last_modified(datetime.datetime): timestamp of the last package submission
|
||||||
url_path(str): AUR package path
|
url_path(str): AUR package path
|
||||||
|
repository(str): repository name of the package
|
||||||
depends(List[str]): list of package dependencies
|
depends(List[str]): list of package dependencies
|
||||||
make_depends(List[str]): list of package make dependencies
|
make_depends(List[str]): list of package make dependencies
|
||||||
opt_depends(List[str]): list of package optional dependencies
|
opt_depends(List[str]): list of package optional dependencies
|
||||||
@ -70,6 +72,7 @@ class AURPackage:
|
|||||||
url: Optional[str] = None
|
url: Optional[str] = None
|
||||||
out_of_date: Optional[datetime.datetime] = None
|
out_of_date: Optional[datetime.datetime] = None
|
||||||
maintainer: Optional[str] = None
|
maintainer: Optional[str] = None
|
||||||
|
repository: str = "aur"
|
||||||
depends: List[str] = field(default_factory=list)
|
depends: List[str] = field(default_factory=list)
|
||||||
make_depends: List[str] = field(default_factory=list)
|
make_depends: List[str] = field(default_factory=list)
|
||||||
opt_depends: List[str] = field(default_factory=list)
|
opt_depends: List[str] = field(default_factory=list)
|
||||||
@ -94,6 +97,42 @@ class AURPackage:
|
|||||||
properties = cls.convert(dump)
|
properties = cls.convert(dump)
|
||||||
return cls(**filter_json(properties, known_fields))
|
return cls(**filter_json(properties, known_fields))
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_pacman(cls: Type[AURPackage], package: Package) -> AURPackage:
|
||||||
|
"""
|
||||||
|
construct package descriptor from official repository wrapper
|
||||||
|
|
||||||
|
Args:
|
||||||
|
package(Package): pyalpm package descriptor
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
AURPackage: AUR package descriptor
|
||||||
|
"""
|
||||||
|
return cls(
|
||||||
|
id=0,
|
||||||
|
name=package.name,
|
||||||
|
package_base_id=0,
|
||||||
|
package_base=package.base,
|
||||||
|
version=package.version,
|
||||||
|
description=package.desc,
|
||||||
|
num_votes=0,
|
||||||
|
popularity=0.0,
|
||||||
|
first_submitted=datetime.datetime.utcfromtimestamp(0),
|
||||||
|
last_modified=datetime.datetime.utcfromtimestamp(package.builddate),
|
||||||
|
url_path="",
|
||||||
|
url=package.url,
|
||||||
|
out_of_date=None,
|
||||||
|
maintainer=None,
|
||||||
|
repository=package.db.name,
|
||||||
|
depends=package.depends,
|
||||||
|
make_depends=package.makedepends,
|
||||||
|
opt_depends=package.optdepends,
|
||||||
|
conflicts=package.conflicts,
|
||||||
|
provides=package.provides,
|
||||||
|
license=package.licenses,
|
||||||
|
keywords=[],
|
||||||
|
)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_repo(cls: Type[AURPackage], dump: Dict[str, Any]) -> AURPackage:
|
def from_repo(cls: Type[AURPackage], dump: Dict[str, Any]) -> AURPackage:
|
||||||
"""
|
"""
|
||||||
@ -122,6 +161,7 @@ class AURPackage:
|
|||||||
dump["flag_date"],
|
dump["flag_date"],
|
||||||
"%Y-%m-%dT%H:%M:%S.%fZ") if dump["flag_date"] is not None else None,
|
"%Y-%m-%dT%H:%M:%S.%fZ") if dump["flag_date"] is not None else None,
|
||||||
maintainer=next(iter(dump["maintainers"]), None),
|
maintainer=next(iter(dump["maintainers"]), None),
|
||||||
|
repository=dump["repo"],
|
||||||
depends=dump["depends"],
|
depends=dump["depends"],
|
||||||
make_depends=dump["makedepends"],
|
make_depends=dump["makedepends"],
|
||||||
opt_depends=dump["optdepends"],
|
opt_depends=dump["optdepends"],
|
||||||
|
@ -23,7 +23,7 @@ from enum import Enum
|
|||||||
from typing import Type
|
from typing import Type
|
||||||
|
|
||||||
|
|
||||||
class AuthSettings(Enum):
|
class AuthSettings(str, Enum):
|
||||||
"""
|
"""
|
||||||
web authorization type
|
web authorization type
|
||||||
|
|
||||||
|
@ -28,7 +28,7 @@ from typing import Any, Dict, Type
|
|||||||
from ahriman.core.util import filter_json, pretty_datetime
|
from ahriman.core.util import filter_json, pretty_datetime
|
||||||
|
|
||||||
|
|
||||||
class BuildStatusEnum(Enum):
|
class BuildStatusEnum(str, Enum):
|
||||||
"""
|
"""
|
||||||
build status enumeration
|
build status enumeration
|
||||||
|
|
||||||
|
@ -26,15 +26,17 @@ from dataclasses import asdict, dataclass
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from pyalpm import vercmp # type: ignore
|
from pyalpm import vercmp # type: ignore
|
||||||
from srcinfo.parse import parse_srcinfo # type: ignore
|
from srcinfo.parse import parse_srcinfo # type: ignore
|
||||||
from typing import Any, Dict, Iterable, List, Set, Type
|
from typing import Any, Dict, Iterable, List, Optional, Set, Type
|
||||||
|
|
||||||
from ahriman.core.alpm.pacman import Pacman
|
from ahriman.core.alpm.pacman import Pacman
|
||||||
from ahriman.core.alpm.remote.aur import AUR
|
from ahriman.core.alpm.remote.aur import AUR
|
||||||
from ahriman.core.alpm.remote.official import Official
|
from ahriman.core.alpm.remote.official import Official
|
||||||
|
from ahriman.core.alpm.remote.official_syncdb import OfficialSyncdb
|
||||||
from ahriman.core.exceptions import InvalidPackageInfo
|
from ahriman.core.exceptions import InvalidPackageInfo
|
||||||
from ahriman.core.util import check_output, full_version
|
from ahriman.core.util import check_output, full_version
|
||||||
from ahriman.models.package_description import PackageDescription
|
from ahriman.models.package_description import PackageDescription
|
||||||
from ahriman.models.package_source import PackageSource
|
from ahriman.models.package_source import PackageSource
|
||||||
|
from ahriman.models.remote_source import RemoteSource
|
||||||
from ahriman.models.repository_paths import RepositoryPaths
|
from ahriman.models.repository_paths import RepositoryPaths
|
||||||
|
|
||||||
|
|
||||||
@ -44,15 +46,16 @@ class Package:
|
|||||||
package properties representation
|
package properties representation
|
||||||
|
|
||||||
Attributes:
|
Attributes:
|
||||||
aur_url(str): AUR root url
|
|
||||||
base(str): package base name
|
base(str): package base name
|
||||||
packages(Dict[str, PackageDescription): map of package names to their properties. Filled only on load from archive
|
packages(Dict[str, PackageDescription): map of package names to their properties.
|
||||||
|
Filled only on load from archive
|
||||||
|
remote(Optional[RemoteSource]): package remote source if applicable
|
||||||
version(str): package full version
|
version(str): package full version
|
||||||
"""
|
"""
|
||||||
|
|
||||||
base: str
|
base: str
|
||||||
version: str
|
version: str
|
||||||
aur_url: str
|
remote: Optional[RemoteSource]
|
||||||
packages: Dict[str, PackageDescription]
|
packages: Dict[str, PackageDescription]
|
||||||
|
|
||||||
_check_output = check_output
|
_check_output = check_output
|
||||||
@ -67,16 +70,6 @@ class Package:
|
|||||||
"""
|
"""
|
||||||
return sorted(set(sum([package.depends for package in self.packages.values()], start=[])))
|
return sorted(set(sum([package.depends for package in self.packages.values()], start=[])))
|
||||||
|
|
||||||
@property
|
|
||||||
def git_url(self) -> str:
|
|
||||||
"""
|
|
||||||
get git clone url
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
str: package git url to clone
|
|
||||||
"""
|
|
||||||
return f"{self.aur_url}/{self.base}.git"
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def groups(self) -> List[str]:
|
def groups(self) -> List[str]:
|
||||||
"""
|
"""
|
||||||
@ -122,56 +115,46 @@ class Package:
|
|||||||
"""
|
"""
|
||||||
return sorted(set(sum([package.licenses for package in self.packages.values()], start=[])))
|
return sorted(set(sum([package.licenses for package in self.packages.values()], start=[])))
|
||||||
|
|
||||||
@property
|
|
||||||
def web_url(self) -> str:
|
|
||||||
"""
|
|
||||||
get package url which can be used to see package in web
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
str: package AUR url
|
|
||||||
"""
|
|
||||||
return f"{self.aur_url}/packages/{self.base}"
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_archive(cls: Type[Package], path: Path, pacman: Pacman, aur_url: str) -> Package:
|
def from_archive(cls: Type[Package], path: Path, pacman: Pacman, remote: Optional[RemoteSource]) -> Package:
|
||||||
"""
|
"""
|
||||||
construct package properties from package archive
|
construct package properties from package archive
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
path(Path): path to package archive
|
path(Path): path to package archive
|
||||||
pacman(Pacman): alpm wrapper instance
|
pacman(Pacman): alpm wrapper instance
|
||||||
aur_url(str): AUR root url
|
remote(RemoteSource): package remote source if applicable
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Package: package properties
|
Package: package properties
|
||||||
"""
|
"""
|
||||||
package = pacman.handle.load_pkg(str(path))
|
package = pacman.handle.load_pkg(str(path))
|
||||||
return cls(package.base, package.version, aur_url,
|
description = PackageDescription.from_package(package, path)
|
||||||
{package.name: PackageDescription.from_package(package, path)})
|
return cls(package.base, package.version, remote, {package.name: description})
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_aur(cls: Type[Package], name: str, aur_url: str) -> Package:
|
def from_aur(cls: Type[Package], name: str, pacman: Pacman) -> Package:
|
||||||
"""
|
"""
|
||||||
construct package properties from AUR page
|
construct package properties from AUR page
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
name(str): package name (either base or normal name)
|
name(str): package name (either base or normal name)
|
||||||
aur_url(str): AUR root url
|
pacman(Pacman): alpm wrapper instance
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Package: package properties
|
Package: package properties
|
||||||
"""
|
"""
|
||||||
package = AUR.info(name)
|
package = AUR.info(name, pacman=pacman)
|
||||||
return cls(package.package_base, package.version, aur_url, {package.name: PackageDescription()})
|
remote = RemoteSource.from_remote(PackageSource.AUR, package.package_base, package.repository)
|
||||||
|
return cls(package.package_base, package.version, remote, {package.name: PackageDescription()})
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_build(cls: Type[Package], path: Path, aur_url: str) -> Package:
|
def from_build(cls: Type[Package], path: Path) -> Package:
|
||||||
"""
|
"""
|
||||||
construct package properties from sources directory
|
construct package properties from sources directory
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
path(Path): path to package sources directory
|
path(Path): path to package sources directory
|
||||||
aur_url(str): AUR root url
|
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Package: package properties
|
Package: package properties
|
||||||
@ -179,13 +162,14 @@ class Package:
|
|||||||
Raises:
|
Raises:
|
||||||
InvalidPackageInfo: if there are parsing errors
|
InvalidPackageInfo: if there are parsing errors
|
||||||
"""
|
"""
|
||||||
srcinfo, errors = parse_srcinfo((path / ".SRCINFO").read_text())
|
srcinfo_source = Package._check_output("makepkg", "--printsrcinfo", exception=None, cwd=path)
|
||||||
|
srcinfo, errors = parse_srcinfo(srcinfo_source)
|
||||||
if errors:
|
if errors:
|
||||||
raise InvalidPackageInfo(errors)
|
raise InvalidPackageInfo(errors)
|
||||||
packages = {key: PackageDescription() for key in srcinfo["packages"]}
|
packages = {key: PackageDescription() for key in srcinfo["packages"]}
|
||||||
version = 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)
|
return cls(srcinfo["pkgbase"], version, None, packages)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_json(cls: Type[Package], dump: Dict[str, Any]) -> Package:
|
def from_json(cls: Type[Package], dump: Dict[str, Any]) -> Package:
|
||||||
@ -202,59 +186,29 @@ class Package:
|
|||||||
key: PackageDescription.from_json(value)
|
key: PackageDescription.from_json(value)
|
||||||
for key, value in dump.get("packages", {}).items()
|
for key, value in dump.get("packages", {}).items()
|
||||||
}
|
}
|
||||||
return Package(
|
remote = dump.get("remote", {})
|
||||||
|
return cls(
|
||||||
base=dump["base"],
|
base=dump["base"],
|
||||||
version=dump["version"],
|
version=dump["version"],
|
||||||
aur_url=dump["aur_url"],
|
remote=RemoteSource.from_json(remote),
|
||||||
packages=packages)
|
packages=packages)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_official(cls: Type[Package], name: str, aur_url: str) -> Package:
|
def from_official(cls: Type[Package], name: str, pacman: Pacman, use_syncdb: bool = True) -> Package:
|
||||||
"""
|
"""
|
||||||
construct package properties from official repository page
|
construct package properties from official repository page
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
name(str): package name (either base or normal name)
|
name(str): package name (either base or normal name)
|
||||||
aur_url(str): AUR root url
|
pacman(Pacman): alpm wrapper instance
|
||||||
|
use_syncdb(bool): use pacman databases instead of official repositories RPC (Default value = True)
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Package: package properties
|
Package: package properties
|
||||||
"""
|
"""
|
||||||
package = Official.info(name)
|
package = OfficialSyncdb.info(name, pacman=pacman) if use_syncdb else Official.info(name, pacman=pacman)
|
||||||
return cls(package.package_base, package.version, aur_url, {package.name: PackageDescription()})
|
remote = RemoteSource.from_remote(PackageSource.Repository, package.package_base, package.repository)
|
||||||
|
return cls(package.package_base, package.version, remote, {package.name: PackageDescription()})
|
||||||
@classmethod
|
|
||||||
def load(cls: Type[Package], package: str, source: PackageSource, pacman: Pacman, aur_url: str) -> Package:
|
|
||||||
"""
|
|
||||||
package constructor from available sources
|
|
||||||
|
|
||||||
Args:
|
|
||||||
package(str): one of path to sources directory, path to archive or package name/base
|
|
||||||
source(PackageSource): source of the package required to define the load method
|
|
||||||
pacman(Pacman): alpm wrapper instance (required to load from archive)
|
|
||||||
aur_url(str): AUR root url
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
Package: package properties
|
|
||||||
|
|
||||||
Raises:
|
|
||||||
InvalidPackageInfo: if supplied package source is not valid
|
|
||||||
"""
|
|
||||||
try:
|
|
||||||
resolved_source = source.resolve(package)
|
|
||||||
if resolved_source == PackageSource.Archive:
|
|
||||||
return cls.from_archive(Path(package), pacman, aur_url)
|
|
||||||
if resolved_source == PackageSource.AUR:
|
|
||||||
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
|
|
||||||
except Exception as e:
|
|
||||||
raise InvalidPackageInfo(str(e))
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def dependencies(path: Path) -> Set[str]:
|
def dependencies(path: Path) -> Set[str]:
|
||||||
@ -279,7 +233,8 @@ class Package:
|
|||||||
package_name = package_name.split(symbol)[0]
|
package_name = package_name.split(symbol)[0]
|
||||||
return package_name
|
return package_name
|
||||||
|
|
||||||
srcinfo, errors = parse_srcinfo((path / ".SRCINFO").read_text())
|
srcinfo_source = Package._check_output("makepkg", "--printsrcinfo", exception=None, cwd=path)
|
||||||
|
srcinfo, errors = parse_srcinfo(srcinfo_source)
|
||||||
if errors:
|
if errors:
|
||||||
raise InvalidPackageInfo(errors)
|
raise InvalidPackageInfo(errors)
|
||||||
makedepends = extract_packages(srcinfo.get("makedepends", []))
|
makedepends = extract_packages(srcinfo.get("makedepends", []))
|
||||||
@ -310,7 +265,7 @@ class Package:
|
|||||||
from ahriman.core.build_tools.sources import Sources
|
from ahriman.core.build_tools.sources import Sources
|
||||||
|
|
||||||
logger = logging.getLogger("build_details")
|
logger = logging.getLogger("build_details")
|
||||||
Sources.load(paths.cache_for(self.base), self.git_url, None)
|
Sources.load(paths.cache_for(self.base), self.remote, None)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# update pkgver first
|
# update pkgver first
|
||||||
|
@ -26,7 +26,7 @@ from urllib.parse import urlparse
|
|||||||
from ahriman.core.util import package_like
|
from ahriman.core.util import package_like
|
||||||
|
|
||||||
|
|
||||||
class PackageSource(Enum):
|
class PackageSource(str, Enum):
|
||||||
"""
|
"""
|
||||||
package source for addition enumeration
|
package source for addition enumeration
|
||||||
|
|
||||||
|
124
src/ahriman/models/remote_source.py
Normal file
124
src/ahriman/models/remote_source.py
Normal file
@ -0,0 +1,124 @@
|
|||||||
|
#
|
||||||
|
# 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
|
||||||
|
|
||||||
|
from dataclasses import asdict, dataclass, fields
|
||||||
|
from pathlib import Path
|
||||||
|
from typing import Any, Dict, Optional, Type
|
||||||
|
|
||||||
|
from ahriman.core.util import filter_json
|
||||||
|
from ahriman.models.package_source import PackageSource
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class RemoteSource:
|
||||||
|
"""
|
||||||
|
remote package source properties
|
||||||
|
|
||||||
|
Attributes:
|
||||||
|
branch(str): branch of the git repository
|
||||||
|
git_url(str): url of the git repository
|
||||||
|
path(str): path to directory with PKGBUILD inside the git repository
|
||||||
|
source(PackageSource): package source pointer used by some parsers
|
||||||
|
web_url(str): url of the package in the web interface
|
||||||
|
"""
|
||||||
|
|
||||||
|
git_url: str
|
||||||
|
web_url: str
|
||||||
|
path: str
|
||||||
|
branch: str
|
||||||
|
source: PackageSource
|
||||||
|
|
||||||
|
def __post_init__(self) -> None:
|
||||||
|
"""
|
||||||
|
convert source to enum type
|
||||||
|
"""
|
||||||
|
self.source = PackageSource(self.source)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def pkgbuild_dir(self) -> Path:
|
||||||
|
"""
|
||||||
|
get path to directory with package sources (PKGBUILD etc)
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Path: path to directory with package sources based on settings
|
||||||
|
"""
|
||||||
|
return Path(self.path)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_json(cls: Type[RemoteSource], dump: Dict[str, Any]) -> Optional[RemoteSource]:
|
||||||
|
"""
|
||||||
|
construct remote source from the json dump (or database row)
|
||||||
|
|
||||||
|
Args:
|
||||||
|
dump(Dict[str, Any]): json dump body
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Optional[RemoteSource]: remote source
|
||||||
|
"""
|
||||||
|
# filter to only known fields
|
||||||
|
known_fields = [pair.name for pair in fields(cls)]
|
||||||
|
dump = filter_json(dump, known_fields)
|
||||||
|
if dump:
|
||||||
|
return cls(**dump)
|
||||||
|
return None
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_remote(cls: Type[RemoteSource], source: PackageSource, package_base: str,
|
||||||
|
repository: str) -> Optional[RemoteSource]:
|
||||||
|
"""
|
||||||
|
generate remote source from the package base
|
||||||
|
|
||||||
|
Args:
|
||||||
|
source(PackageSource): source of the package
|
||||||
|
package_base(str): package base
|
||||||
|
repository(str): repository name
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Optional[RemoteSource]: generated remote source if any, None otherwise
|
||||||
|
"""
|
||||||
|
if source == PackageSource.AUR:
|
||||||
|
from ahriman.core.alpm.remote.aur import AUR
|
||||||
|
return RemoteSource(
|
||||||
|
git_url=AUR.remote_git_url(package_base, repository),
|
||||||
|
web_url=AUR.remote_web_url(package_base),
|
||||||
|
path=".",
|
||||||
|
branch="master",
|
||||||
|
source=source,
|
||||||
|
)
|
||||||
|
if source == PackageSource.Repository:
|
||||||
|
from ahriman.core.alpm.remote.official import Official
|
||||||
|
return RemoteSource(
|
||||||
|
git_url=Official.remote_git_url(package_base, repository),
|
||||||
|
web_url=Official.remote_web_url(package_base),
|
||||||
|
path="trunk",
|
||||||
|
branch=f"packages/{package_base}",
|
||||||
|
source=source,
|
||||||
|
)
|
||||||
|
return None
|
||||||
|
|
||||||
|
def view(self) -> Dict[str, Any]:
|
||||||
|
"""
|
||||||
|
generate json package remote view
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Dict[str, Any]: json-friendly dictionary
|
||||||
|
"""
|
||||||
|
return asdict(self)
|
@ -23,7 +23,7 @@ from enum import Enum
|
|||||||
from typing import Type
|
from typing import Type
|
||||||
|
|
||||||
|
|
||||||
class ReportSettings(Enum):
|
class ReportSettings(str, Enum):
|
||||||
"""
|
"""
|
||||||
report targets enumeration
|
report targets enumeration
|
||||||
|
|
||||||
|
@ -23,7 +23,7 @@ from enum import Enum
|
|||||||
from typing import Type
|
from typing import Type
|
||||||
|
|
||||||
|
|
||||||
class SignSettings(Enum):
|
class SignSettings(str, Enum):
|
||||||
"""
|
"""
|
||||||
sign targets enumeration
|
sign targets enumeration
|
||||||
|
|
||||||
|
@ -23,7 +23,7 @@ from enum import Enum
|
|||||||
from typing import Type
|
from typing import Type
|
||||||
|
|
||||||
|
|
||||||
class SmtpSSLSettings(Enum):
|
class SmtpSSLSettings(str, Enum):
|
||||||
"""
|
"""
|
||||||
SMTP SSL mode enumeration
|
SMTP SSL mode enumeration
|
||||||
|
|
||||||
|
@ -23,7 +23,7 @@ from enum import Enum
|
|||||||
from typing import Type
|
from typing import Type
|
||||||
|
|
||||||
|
|
||||||
class UploadSettings(Enum):
|
class UploadSettings(str, Enum):
|
||||||
"""
|
"""
|
||||||
remote synchronization targets enumeration
|
remote synchronization targets enumeration
|
||||||
|
|
||||||
|
@ -20,7 +20,7 @@
|
|||||||
from enum import Enum
|
from enum import Enum
|
||||||
|
|
||||||
|
|
||||||
class UserAccess(Enum):
|
class UserAccess(str, Enum):
|
||||||
"""
|
"""
|
||||||
web user access enumeration
|
web user access enumeration
|
||||||
|
|
||||||
|
@ -86,7 +86,7 @@ class IndexView(BaseView):
|
|||||||
"status_color": status.status.bootstrap_color(),
|
"status_color": status.status.bootstrap_color(),
|
||||||
"timestamp": pretty_datetime(status.timestamp),
|
"timestamp": pretty_datetime(status.timestamp),
|
||||||
"version": package.version,
|
"version": package.version,
|
||||||
"web_url": package.web_url,
|
"web_url": package.remote.web_url if package.remote is not None else None,
|
||||||
} for package, status in sorted(self.service.packages, key=lambda item: item[0].base)
|
} for package, status in sorted(self.service.packages, key=lambda item: item[0].base)
|
||||||
]
|
]
|
||||||
service = {
|
service = {
|
||||||
|
@ -50,7 +50,7 @@ class SearchView(BaseView):
|
|||||||
HTTPNotFound: if no packages found
|
HTTPNotFound: if no packages found
|
||||||
"""
|
"""
|
||||||
search: List[str] = self.request.query.getall("for", default=[])
|
search: List[str] = self.request.query.getall("for", default=[])
|
||||||
packages = AUR.multisearch(*search)
|
packages = AUR.multisearch(*search, pacman=self.service.repository.pacman)
|
||||||
if not packages:
|
if not packages:
|
||||||
raise HTTPNotFound(reason=f"No packages found for terms: {search}")
|
raise HTTPNotFound(reason=f"No packages found for terms: {search}")
|
||||||
|
|
||||||
|
@ -44,19 +44,21 @@ def test_add_aur(application_packages: ApplicationPackages, package_ahriman: Pac
|
|||||||
"""
|
"""
|
||||||
must add package from AUR
|
must add package from AUR
|
||||||
"""
|
"""
|
||||||
mocker.patch("ahriman.models.package.Package.load", return_value=package_ahriman)
|
mocker.patch("ahriman.models.package.Package.from_aur", return_value=package_ahriman)
|
||||||
load_mock = mocker.patch("ahriman.core.build_tools.sources.Sources.load")
|
load_mock = mocker.patch("ahriman.core.build_tools.sources.Sources.load")
|
||||||
dependencies_mock = mocker.patch(
|
dependencies_mock = mocker.patch(
|
||||||
"ahriman.application.application.application_packages.ApplicationPackages._process_dependencies")
|
"ahriman.application.application.application_packages.ApplicationPackages._process_dependencies")
|
||||||
build_queue_mock = mocker.patch("ahriman.core.database.sqlite.SQLite.build_queue_insert")
|
build_queue_mock = mocker.patch("ahriman.core.database.sqlite.SQLite.build_queue_insert")
|
||||||
|
update_remote_mock = mocker.patch("ahriman.core.database.sqlite.SQLite.remote_update")
|
||||||
|
|
||||||
application_packages._add_aur(package_ahriman.base, set(), False)
|
application_packages._add_aur(package_ahriman.base, set(), False)
|
||||||
load_mock.assert_called_once_with(
|
load_mock.assert_called_once_with(
|
||||||
pytest.helpers.anyvar(int),
|
pytest.helpers.anyvar(int),
|
||||||
package_ahriman.git_url,
|
package_ahriman.remote,
|
||||||
pytest.helpers.anyvar(int))
|
pytest.helpers.anyvar(int))
|
||||||
dependencies_mock.assert_called_once_with(pytest.helpers.anyvar(int), set(), False)
|
dependencies_mock.assert_called_once_with(pytest.helpers.anyvar(int), set(), False)
|
||||||
build_queue_mock.assert_called_once_with(package_ahriman)
|
build_queue_mock.assert_called_once_with(package_ahriman)
|
||||||
|
update_remote_mock.assert_called_once_with(package_ahriman)
|
||||||
|
|
||||||
|
|
||||||
def test_add_directory(
|
def test_add_directory(
|
||||||
@ -80,7 +82,7 @@ def test_add_local(application_packages: ApplicationPackages, package_ahriman: P
|
|||||||
"""
|
"""
|
||||||
must add package from local sources
|
must add package from local sources
|
||||||
"""
|
"""
|
||||||
mocker.patch("ahriman.models.package.Package.load", return_value=package_ahriman)
|
mocker.patch("ahriman.models.package.Package.from_build", return_value=package_ahriman)
|
||||||
init_mock = mocker.patch("ahriman.core.build_tools.sources.Sources.init")
|
init_mock = mocker.patch("ahriman.core.build_tools.sources.Sources.init")
|
||||||
copytree_mock = mocker.patch("shutil.copytree")
|
copytree_mock = mocker.patch("shutil.copytree")
|
||||||
dependencies_mock = mocker.patch(
|
dependencies_mock = mocker.patch(
|
||||||
@ -112,6 +114,20 @@ def test_add_remote(application_packages: ApplicationPackages, package_descripti
|
|||||||
response_mock.raise_for_status.assert_called_once_with()
|
response_mock.raise_for_status.assert_called_once_with()
|
||||||
|
|
||||||
|
|
||||||
|
def test_add_repository(application_packages: ApplicationPackages, package_ahriman: Package,
|
||||||
|
mocker: MockerFixture) -> None:
|
||||||
|
"""
|
||||||
|
must add package from official repository
|
||||||
|
"""
|
||||||
|
mocker.patch("ahriman.models.package.Package.from_official", return_value=package_ahriman)
|
||||||
|
build_queue_mock = mocker.patch("ahriman.core.database.sqlite.SQLite.build_queue_insert")
|
||||||
|
update_remote_mock = mocker.patch("ahriman.core.database.sqlite.SQLite.remote_update")
|
||||||
|
|
||||||
|
application_packages._add_repository(package_ahriman.base)
|
||||||
|
build_queue_mock.assert_called_once_with(package_ahriman)
|
||||||
|
update_remote_mock.assert_called_once_with(package_ahriman)
|
||||||
|
|
||||||
|
|
||||||
def test_process_dependencies(application_packages: ApplicationPackages, mocker: MockerFixture) -> None:
|
def test_process_dependencies(application_packages: ApplicationPackages, mocker: MockerFixture) -> None:
|
||||||
"""
|
"""
|
||||||
must process dependencies addition
|
must process dependencies addition
|
||||||
|
@ -14,7 +14,7 @@ def test_finalize(application_repository: ApplicationRepository) -> None:
|
|||||||
must raise NotImplemented for missing finalize method
|
must raise NotImplemented for missing finalize method
|
||||||
"""
|
"""
|
||||||
with pytest.raises(NotImplementedError):
|
with pytest.raises(NotImplementedError):
|
||||||
application_repository._finalize([])
|
application_repository._finalize(Result())
|
||||||
|
|
||||||
|
|
||||||
def test_clean_cache(application_repository: ApplicationRepository, mocker: MockerFixture) -> None:
|
def test_clean_cache(application_repository: ApplicationRepository, mocker: MockerFixture) -> None:
|
||||||
@ -58,8 +58,8 @@ def test_report(application_repository: ApplicationRepository, mocker: MockerFix
|
|||||||
must generate report
|
must generate report
|
||||||
"""
|
"""
|
||||||
executor_mock = mocker.patch("ahriman.core.repository.executor.Executor.process_report")
|
executor_mock = mocker.patch("ahriman.core.repository.executor.Executor.process_report")
|
||||||
application_repository.report(["a"], [])
|
application_repository.report(["a"], Result())
|
||||||
executor_mock.assert_called_once_with(["a"], [])
|
executor_mock.assert_called_once_with(["a"], Result())
|
||||||
|
|
||||||
|
|
||||||
def test_sign(application_repository: ApplicationRepository, package_ahriman: Package, package_python_schedule: Package,
|
def test_sign(application_repository: ApplicationRepository, package_ahriman: Package, package_python_schedule: Package,
|
||||||
@ -179,7 +179,6 @@ def test_update(application_repository: ApplicationRepository, package_ahriman:
|
|||||||
|
|
||||||
mocker.patch("ahriman.core.tree.Tree.load", return_value=tree)
|
mocker.patch("ahriman.core.tree.Tree.load", return_value=tree)
|
||||||
mocker.patch("ahriman.core.repository.repository.Repository.packages_built", return_value=paths)
|
mocker.patch("ahriman.core.repository.repository.Repository.packages_built", return_value=paths)
|
||||||
mocker.patch("ahriman.models.package.Package.load", return_value=package_ahriman)
|
|
||||||
build_mock = mocker.patch("ahriman.core.repository.executor.Executor.process_build", return_value=result)
|
build_mock = mocker.patch("ahriman.core.repository.executor.Executor.process_build", return_value=result)
|
||||||
update_mock = mocker.patch("ahriman.core.repository.executor.Executor.process_update", return_value=result)
|
update_mock = mocker.patch("ahriman.core.repository.executor.Executor.process_update", return_value=result)
|
||||||
finalize_mock = mocker.patch(
|
finalize_mock = mocker.patch(
|
||||||
@ -201,7 +200,6 @@ def test_update_empty(application_repository: ApplicationRepository, package_ahr
|
|||||||
|
|
||||||
mocker.patch("ahriman.core.tree.Tree.load", return_value=tree)
|
mocker.patch("ahriman.core.tree.Tree.load", return_value=tree)
|
||||||
mocker.patch("ahriman.core.repository.repository.Repository.packages_built", return_value=[])
|
mocker.patch("ahriman.core.repository.repository.Repository.packages_built", return_value=[])
|
||||||
mocker.patch("ahriman.models.package.Package.load", return_value=package_ahriman)
|
|
||||||
mocker.patch("ahriman.core.repository.executor.Executor.process_build")
|
mocker.patch("ahriman.core.repository.executor.Executor.process_build")
|
||||||
update_mock = mocker.patch("ahriman.core.repository.executor.Executor.process_update")
|
update_mock = mocker.patch("ahriman.core.repository.executor.Executor.process_update")
|
||||||
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import argparse
|
import argparse
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
|
from pathlib import Path
|
||||||
from pytest_mock import MockerFixture
|
from pytest_mock import MockerFixture
|
||||||
|
|
||||||
from ahriman.application.application import Application
|
from ahriman.application.application import Application
|
||||||
@ -37,7 +38,7 @@ def test_run(args: argparse.Namespace, configuration: Configuration, mocker: Moc
|
|||||||
application_mock = mocker.patch("ahriman.application.handlers.patch.Patch.patch_set_create")
|
application_mock = mocker.patch("ahriman.application.handlers.patch.Patch.patch_set_create")
|
||||||
|
|
||||||
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, args.track)
|
application_mock.assert_called_once_with(pytest.helpers.anyvar(int), Path(args.package), args.track)
|
||||||
|
|
||||||
|
|
||||||
def test_run_list(args: argparse.Namespace, configuration: Configuration, mocker: MockerFixture) -> None:
|
def test_run_list(args: argparse.Namespace, configuration: Configuration, mocker: MockerFixture) -> None:
|
||||||
@ -96,11 +97,11 @@ 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("pathlib.Path.mkdir")
|
||||||
mocker.patch("ahriman.models.package.Package.load", return_value=package_ahriman)
|
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")
|
mocker.patch("ahriman.core.build_tools.sources.Sources.patch_create", return_value="patch")
|
||||||
create_mock = mocker.patch("ahriman.core.database.sqlite.SQLite.patches_insert")
|
create_mock = mocker.patch("ahriman.core.database.sqlite.SQLite.patches_insert")
|
||||||
|
|
||||||
Patch.patch_set_create(application, "path", ["*.patch"])
|
Patch.patch_set_create(application, Path("path"), ["*.patch"])
|
||||||
create_mock.assert_called_once_with(package_ahriman.base, "patch")
|
create_mock.assert_called_once_with(package_ahriman.base, "patch")
|
||||||
|
|
||||||
|
|
||||||
|
@ -34,6 +34,7 @@ def test_run(args: argparse.Namespace, configuration: Configuration, aur_package
|
|||||||
must run command
|
must run command
|
||||||
"""
|
"""
|
||||||
args = _default_args(args)
|
args = _default_args(args)
|
||||||
|
mocker.patch("ahriman.models.repository_paths.RepositoryPaths.tree_create")
|
||||||
aur_search_mock = mocker.patch("ahriman.core.alpm.remote.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",
|
official_search_mock = mocker.patch("ahriman.core.alpm.remote.official.Official.multisearch",
|
||||||
return_value=[aur_package_ahriman])
|
return_value=[aur_package_ahriman])
|
||||||
@ -41,8 +42,8 @@ def test_run(args: argparse.Namespace, configuration: Configuration, aur_package
|
|||||||
print_mock = mocker.patch("ahriman.core.formatters.printer.Printer.print")
|
print_mock = mocker.patch("ahriman.core.formatters.printer.Printer.print")
|
||||||
|
|
||||||
Search.run(args, "x86_64", configuration, True, False)
|
Search.run(args, "x86_64", configuration, True, False)
|
||||||
aur_search_mock.assert_called_once_with("ahriman")
|
aur_search_mock.assert_called_once_with("ahriman", pacman=pytest.helpers.anyvar(int))
|
||||||
official_search_mock.assert_called_once_with("ahriman")
|
official_search_mock.assert_called_once_with("ahriman", pacman=pytest.helpers.anyvar(int))
|
||||||
check_mock.assert_called_once_with(False, False)
|
check_mock.assert_called_once_with(False, False)
|
||||||
print_mock.assert_has_calls([mock.call(False), mock.call(False)])
|
print_mock.assert_has_calls([mock.call(False), mock.call(False)])
|
||||||
|
|
||||||
@ -56,6 +57,7 @@ def test_run_empty_exception(args: argparse.Namespace, configuration: Configurat
|
|||||||
mocker.patch("ahriman.core.alpm.remote.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.alpm.remote.official.Official.multisearch", return_value=[])
|
||||||
mocker.patch("ahriman.core.formatters.printer.Printer.print")
|
mocker.patch("ahriman.core.formatters.printer.Printer.print")
|
||||||
|
mocker.patch("ahriman.models.repository_paths.RepositoryPaths.tree_create")
|
||||||
check_mock = mocker.patch("ahriman.application.handlers.handler.Handler.check_if_empty")
|
check_mock = mocker.patch("ahriman.application.handlers.handler.Handler.check_if_empty")
|
||||||
|
|
||||||
Search.run(args, "x86_64", configuration, True, False)
|
Search.run(args, "x86_64", configuration, True, False)
|
||||||
@ -70,6 +72,7 @@ def test_run_sort(args: argparse.Namespace, configuration: Configuration, aur_pa
|
|||||||
args = _default_args(args)
|
args = _default_args(args)
|
||||||
mocker.patch("ahriman.core.alpm.remote.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=[])
|
mocker.patch("ahriman.core.alpm.remote.official.Official.multisearch", return_value=[])
|
||||||
|
mocker.patch("ahriman.models.repository_paths.RepositoryPaths.tree_create")
|
||||||
sort_mock = mocker.patch("ahriman.application.handlers.search.Search.sort")
|
sort_mock = mocker.patch("ahriman.application.handlers.search.Search.sort")
|
||||||
|
|
||||||
Search.run(args, "x86_64", configuration, True, False)
|
Search.run(args, "x86_64", configuration, True, False)
|
||||||
@ -88,6 +91,7 @@ def test_run_sort_by(args: argparse.Namespace, configuration: Configuration, aur
|
|||||||
args.sort_by = "field"
|
args.sort_by = "field"
|
||||||
mocker.patch("ahriman.core.alpm.remote.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=[])
|
mocker.patch("ahriman.core.alpm.remote.official.Official.multisearch", return_value=[])
|
||||||
|
mocker.patch("ahriman.models.repository_paths.RepositoryPaths.tree_create")
|
||||||
sort_mock = mocker.patch("ahriman.application.handlers.search.Search.sort")
|
sort_mock = mocker.patch("ahriman.application.handlers.search.Search.sort")
|
||||||
|
|
||||||
Search.run(args, "x86_64", configuration, True, False)
|
Search.run(args, "x86_64", configuration, True, False)
|
||||||
|
@ -6,6 +6,7 @@ from pytest_mock import MockerFixture
|
|||||||
from typing import Any, Dict, Type, TypeVar
|
from typing import Any, Dict, Type, TypeVar
|
||||||
from unittest.mock import MagicMock
|
from unittest.mock import MagicMock
|
||||||
|
|
||||||
|
from ahriman.core.alpm.pacman import Pacman
|
||||||
from ahriman.core.auth.auth import Auth
|
from ahriman.core.auth.auth import Auth
|
||||||
from ahriman.core.configuration import Configuration
|
from ahriman.core.configuration import Configuration
|
||||||
from ahriman.core.database.sqlite import SQLite
|
from ahriman.core.database.sqlite import SQLite
|
||||||
@ -15,6 +16,8 @@ from ahriman.models.aur_package import AURPackage
|
|||||||
from ahriman.models.build_status import BuildStatus, BuildStatusEnum
|
from ahriman.models.build_status import BuildStatus, BuildStatusEnum
|
||||||
from ahriman.models.package import Package
|
from ahriman.models.package import Package
|
||||||
from ahriman.models.package_description import PackageDescription
|
from ahriman.models.package_description import PackageDescription
|
||||||
|
from ahriman.models.package_source import PackageSource
|
||||||
|
from ahriman.models.remote_source import RemoteSource
|
||||||
from ahriman.models.repository_paths import RepositoryPaths
|
from ahriman.models.repository_paths import RepositoryPaths
|
||||||
from ahriman.models.result import Result
|
from ahriman.models.result import Result
|
||||||
from ahriman.models.user import User
|
from ahriman.models.user import User
|
||||||
@ -101,8 +104,8 @@ def aur_package_ahriman() -> AURPackage:
|
|||||||
description="ArcH Linux ReposItory MANager",
|
description="ArcH Linux ReposItory MANager",
|
||||||
num_votes=0,
|
num_votes=0,
|
||||||
popularity=0,
|
popularity=0,
|
||||||
first_submitted=datetime.datetime(2021, 4, 9, 22, 44, 45),
|
first_submitted=datetime.datetime.utcfromtimestamp(1618008285),
|
||||||
last_modified=datetime.datetime(2021, 12, 25, 23, 11, 11),
|
last_modified=datetime.datetime.utcfromtimestamp(1640473871),
|
||||||
url_path="/cgit/aur.git/snapshot/ahriman.tar.gz",
|
url_path="/cgit/aur.git/snapshot/ahriman.tar.gz",
|
||||||
url="https://github.com/arcan1s/ahriman",
|
url="https://github.com/arcan1s/ahriman",
|
||||||
out_of_date=None,
|
out_of_date=None,
|
||||||
@ -155,13 +158,14 @@ def aur_package_akonadi() -> AURPackage:
|
|||||||
version="21.12.3-2",
|
version="21.12.3-2",
|
||||||
description="PIM layer, which provides an asynchronous API to access all kind of PIM data",
|
description="PIM layer, which provides an asynchronous API to access all kind of PIM data",
|
||||||
num_votes=0,
|
num_votes=0,
|
||||||
popularity=0,
|
popularity=0.0,
|
||||||
first_submitted=datetime.datetime(1970, 1, 1, 0, 0, 0),
|
first_submitted=datetime.datetime.utcfromtimestamp(0),
|
||||||
last_modified=datetime.datetime(2022, 3, 6, 8, 39, 50, 610000),
|
last_modified=datetime.datetime.utcfromtimestamp(1646555990.610),
|
||||||
url_path="",
|
url_path="",
|
||||||
url="https://kontact.kde.org",
|
url="https://kontact.kde.org",
|
||||||
out_of_date=None,
|
out_of_date=None,
|
||||||
maintainer="felixonmars",
|
maintainer="felixonmars",
|
||||||
|
repository="extra",
|
||||||
depends=[
|
depends=[
|
||||||
"libakonadi",
|
"libakonadi",
|
||||||
"mariadb",
|
"mariadb",
|
||||||
@ -245,7 +249,7 @@ def package_ahriman(package_description_ahriman: PackageDescription) -> Package:
|
|||||||
return Package(
|
return Package(
|
||||||
base="ahriman",
|
base="ahriman",
|
||||||
version="1.7.0-1",
|
version="1.7.0-1",
|
||||||
aur_url="https://aur.archlinux.org",
|
remote=RemoteSource.from_remote(PackageSource.AUR, "ahriman", "aur"),
|
||||||
packages=packages)
|
packages=packages)
|
||||||
|
|
||||||
|
|
||||||
@ -270,7 +274,7 @@ def package_python_schedule(
|
|||||||
return Package(
|
return Package(
|
||||||
base="python-schedule",
|
base="python-schedule",
|
||||||
version="1.0.0-2",
|
version="1.0.0-2",
|
||||||
aur_url="https://aur.archlinux.org",
|
remote=RemoteSource.from_remote(PackageSource.AUR, "python-schedule", "aur"),
|
||||||
packages=packages)
|
packages=packages)
|
||||||
|
|
||||||
|
|
||||||
@ -344,6 +348,34 @@ def package_description_python2_schedule() -> PackageDescription:
|
|||||||
url="https://github.com/dbader/schedule")
|
url="https://github.com/dbader/schedule")
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def pacman(configuration: Configuration) -> Pacman:
|
||||||
|
"""
|
||||||
|
fixture for pacman wrapper
|
||||||
|
|
||||||
|
Args:
|
||||||
|
configuration(Configuration): configuration fixture
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Pacman: pacman wrapper test instance
|
||||||
|
"""
|
||||||
|
return Pacman(configuration)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def remote_source(package_ahriman: Package) -> RemoteSource:
|
||||||
|
"""
|
||||||
|
remote source fixture
|
||||||
|
|
||||||
|
Args:
|
||||||
|
package_ahriman(Package): package fixture
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
RemoteSource: remote source test instance
|
||||||
|
"""
|
||||||
|
return RemoteSource.from_remote(PackageSource.AUR, "ahriman", "aur")
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def repository_paths(configuration: Configuration) -> RepositoryPaths:
|
def repository_paths(configuration: Configuration) -> RepositoryPaths:
|
||||||
"""
|
"""
|
||||||
|
@ -2,6 +2,7 @@ import pytest
|
|||||||
|
|
||||||
from ahriman.core.alpm.remote.aur import AUR
|
from ahriman.core.alpm.remote.aur import AUR
|
||||||
from ahriman.core.alpm.remote.official import Official
|
from ahriman.core.alpm.remote.official import Official
|
||||||
|
from ahriman.core.alpm.remote.official_syncdb import OfficialSyncdb
|
||||||
from ahriman.core.alpm.remote.remote import Remote
|
from ahriman.core.alpm.remote.remote import Remote
|
||||||
|
|
||||||
|
|
||||||
@ -27,6 +28,17 @@ def official() -> Official:
|
|||||||
return Official()
|
return Official()
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def official_syncdb() -> OfficialSyncdb:
|
||||||
|
"""
|
||||||
|
official repository fixture with database processing
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
OfficialSyncdb: official repository with database processing helper instance
|
||||||
|
"""
|
||||||
|
return OfficialSyncdb()
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def remote() -> Remote:
|
def remote() -> Remote:
|
||||||
"""
|
"""
|
||||||
|
@ -6,6 +6,7 @@ from pathlib import Path
|
|||||||
from pytest_mock import MockerFixture
|
from pytest_mock import MockerFixture
|
||||||
from unittest.mock import MagicMock
|
from unittest.mock import MagicMock
|
||||||
|
|
||||||
|
from ahriman.core.alpm.pacman import Pacman
|
||||||
from ahriman.core.alpm.remote.aur import AUR
|
from ahriman.core.alpm.remote.aur import AUR
|
||||||
from ahriman.core.exceptions import InvalidPackageInfo
|
from ahriman.core.exceptions import InvalidPackageInfo
|
||||||
from ahriman.models.aur_package import AURPackage
|
from ahriman.models.aur_package import AURPackage
|
||||||
@ -49,6 +50,23 @@ def test_parse_response_unknown_error() -> None:
|
|||||||
AUR.parse_response({"type": "error"})
|
AUR.parse_response({"type": "error"})
|
||||||
|
|
||||||
|
|
||||||
|
def test_remote_git_url(aur_package_ahriman: AURPackage) -> None:
|
||||||
|
"""
|
||||||
|
must generate package git url
|
||||||
|
"""
|
||||||
|
git_url = AUR.remote_git_url(aur_package_ahriman.package_base, aur_package_ahriman.repository)
|
||||||
|
assert git_url.endswith(".git")
|
||||||
|
assert git_url.startswith(AUR.DEFAULT_AUR_URL)
|
||||||
|
|
||||||
|
|
||||||
|
def test_remote_web_url(aur_package_ahriman: AURPackage) -> None:
|
||||||
|
"""
|
||||||
|
must generate package git url
|
||||||
|
"""
|
||||||
|
web_url = AUR.remote_web_url(aur_package_ahriman.package_base)
|
||||||
|
assert web_url.startswith(AUR.DEFAULT_AUR_URL)
|
||||||
|
|
||||||
|
|
||||||
def test_make_request(aur: AUR, aur_package_ahriman: AURPackage,
|
def test_make_request(aur: AUR, aur_package_ahriman: AURPackage,
|
||||||
mocker: MockerFixture, resource_path_root: Path) -> None:
|
mocker: MockerFixture, resource_path_root: Path) -> None:
|
||||||
"""
|
"""
|
||||||
@ -109,19 +127,19 @@ def test_make_request_failed_http_error(aur: AUR, mocker: MockerFixture) -> None
|
|||||||
aur.make_request("info", "ahriman")
|
aur.make_request("info", "ahriman")
|
||||||
|
|
||||||
|
|
||||||
def test_package_info(aur: AUR, aur_package_ahriman: AURPackage, mocker: MockerFixture) -> None:
|
def test_package_info(aur: AUR, aur_package_ahriman: AURPackage, pacman: Pacman, mocker: MockerFixture) -> None:
|
||||||
"""
|
"""
|
||||||
must make request for info
|
must make request for info
|
||||||
"""
|
"""
|
||||||
request_mock = mocker.patch("ahriman.core.alpm.remote.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
|
assert aur.package_info(aur_package_ahriman.name, pacman=pacman) == aur_package_ahriman
|
||||||
request_mock.assert_called_once_with("info", aur_package_ahriman.name)
|
request_mock.assert_called_once_with("info", aur_package_ahriman.name)
|
||||||
|
|
||||||
|
|
||||||
def test_package_search(aur: AUR, aur_package_ahriman: AURPackage, mocker: MockerFixture) -> None:
|
def test_package_search(aur: AUR, aur_package_ahriman: AURPackage, pacman: Pacman, mocker: MockerFixture) -> None:
|
||||||
"""
|
"""
|
||||||
must make request for search
|
must make request for search
|
||||||
"""
|
"""
|
||||||
request_mock = mocker.patch("ahriman.core.alpm.remote.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_search(aur_package_ahriman.name) == [aur_package_ahriman]
|
assert aur.package_search(aur_package_ahriman.name, pacman=pacman) == [aur_package_ahriman]
|
||||||
request_mock.assert_called_once_with("search", aur_package_ahriman.name, by="name-desc")
|
request_mock.assert_called_once_with("search", aur_package_ahriman.name, by="name-desc")
|
||||||
|
@ -6,6 +6,7 @@ from pathlib import Path
|
|||||||
from pytest_mock import MockerFixture
|
from pytest_mock import MockerFixture
|
||||||
from unittest.mock import MagicMock
|
from unittest.mock import MagicMock
|
||||||
|
|
||||||
|
from ahriman.core.alpm.pacman import Pacman
|
||||||
from ahriman.core.alpm.remote.official import Official
|
from ahriman.core.alpm.remote.official import Official
|
||||||
from ahriman.core.exceptions import InvalidPackageInfo
|
from ahriman.core.exceptions import InvalidPackageInfo
|
||||||
from ahriman.models.aur_package import AURPackage
|
from ahriman.models.aur_package import AURPackage
|
||||||
@ -41,6 +42,38 @@ def test_parse_response_unknown_error(resource_path_root: Path) -> None:
|
|||||||
Official.parse_response(json.loads(response))
|
Official.parse_response(json.loads(response))
|
||||||
|
|
||||||
|
|
||||||
|
def test_remote_git_url(aur_package_akonadi: AURPackage) -> None:
|
||||||
|
"""
|
||||||
|
must generate package git url for core packages
|
||||||
|
"""
|
||||||
|
git_urls = [
|
||||||
|
Official.remote_git_url(aur_package_akonadi.package_base, repository)
|
||||||
|
for repository in ("core", "extra", "Core", "Extra")
|
||||||
|
]
|
||||||
|
assert all(git_url.endswith("svntogit-packages.git") for git_url in git_urls)
|
||||||
|
assert len(set(git_urls)) == 1
|
||||||
|
|
||||||
|
|
||||||
|
def test_remote_git_url_community(aur_package_akonadi: AURPackage) -> None:
|
||||||
|
"""
|
||||||
|
must generate package git url for core packages
|
||||||
|
"""
|
||||||
|
git_urls = [
|
||||||
|
Official.remote_git_url(aur_package_akonadi.package_base, repository)
|
||||||
|
for repository in ("community", "multilib", "Community", "Multilib")
|
||||||
|
]
|
||||||
|
assert all(git_url.endswith("svntogit-community.git") for git_url in git_urls)
|
||||||
|
assert len(set(git_urls)) == 1
|
||||||
|
|
||||||
|
|
||||||
|
def test_remote_web_url(aur_package_akonadi: AURPackage) -> None:
|
||||||
|
"""
|
||||||
|
must generate package git url
|
||||||
|
"""
|
||||||
|
web_url = Official.remote_web_url(aur_package_akonadi.package_base)
|
||||||
|
assert web_url.startswith(Official.DEFAULT_ARCHLINUX_URL)
|
||||||
|
|
||||||
|
|
||||||
def test_make_request(official: Official, aur_package_akonadi: AURPackage,
|
def test_make_request(official: Official, aur_package_akonadi: AURPackage,
|
||||||
mocker: MockerFixture, resource_path_root: Path) -> None:
|
mocker: MockerFixture, resource_path_root: Path) -> None:
|
||||||
"""
|
"""
|
||||||
@ -51,7 +84,8 @@ def test_make_request(official: Official, aur_package_akonadi: AURPackage,
|
|||||||
request_mock = mocker.patch("requests.get", return_value=response_mock)
|
request_mock = mocker.patch("requests.get", return_value=response_mock)
|
||||||
|
|
||||||
assert official.make_request("akonadi", by="q") == [aur_package_akonadi]
|
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",)})
|
request_mock.assert_called_once_with("https://archlinux.org/packages/search/json",
|
||||||
|
params={"q": ("akonadi",), "repo": Official.DEFAULT_SEARCH_REPOSITORIES})
|
||||||
|
|
||||||
|
|
||||||
def test_make_request_failed(official: Official, mocker: MockerFixture) -> None:
|
def test_make_request_failed(official: Official, mocker: MockerFixture) -> None:
|
||||||
@ -72,21 +106,23 @@ def test_make_request_failed_http_error(official: Official, mocker: MockerFixtur
|
|||||||
official.make_request("akonadi", by="q")
|
official.make_request("akonadi", by="q")
|
||||||
|
|
||||||
|
|
||||||
def test_package_info(official: Official, aur_package_akonadi: AURPackage, mocker: MockerFixture) -> None:
|
def test_package_info(official: Official, aur_package_akonadi: AURPackage, pacman: Pacman,
|
||||||
|
mocker: MockerFixture) -> None:
|
||||||
"""
|
"""
|
||||||
must make request for info
|
must make request for info
|
||||||
"""
|
"""
|
||||||
request_mock = mocker.patch("ahriman.core.alpm.remote.official.Official.make_request",
|
request_mock = mocker.patch("ahriman.core.alpm.remote.official.Official.make_request",
|
||||||
return_value=[aur_package_akonadi])
|
return_value=[aur_package_akonadi])
|
||||||
assert official.package_info(aur_package_akonadi.name) == aur_package_akonadi
|
assert official.package_info(aur_package_akonadi.name, pacman=pacman) == aur_package_akonadi
|
||||||
request_mock.assert_called_once_with(aur_package_akonadi.name, by="name")
|
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:
|
def test_package_search(official: Official, aur_package_akonadi: AURPackage, pacman: Pacman,
|
||||||
|
mocker: MockerFixture) -> None:
|
||||||
"""
|
"""
|
||||||
must make request for search
|
must make request for search
|
||||||
"""
|
"""
|
||||||
request_mock = mocker.patch("ahriman.core.alpm.remote.official.Official.make_request",
|
request_mock = mocker.patch("ahriman.core.alpm.remote.official.Official.make_request",
|
||||||
return_value=[aur_package_akonadi])
|
return_value=[aur_package_akonadi])
|
||||||
assert official.package_search(aur_package_akonadi.name) == [aur_package_akonadi]
|
assert official.package_search(aur_package_akonadi.name, pacman=pacman) == [aur_package_akonadi]
|
||||||
request_mock.assert_called_once_with(aur_package_akonadi.name, by="q")
|
request_mock.assert_called_once_with(aur_package_akonadi.name, by="q")
|
||||||
|
18
tests/ahriman/core/alpm/remote/test_official_syncdb.py
Normal file
18
tests/ahriman/core/alpm/remote/test_official_syncdb.py
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
from pytest_mock import MockerFixture
|
||||||
|
|
||||||
|
from ahriman.core.alpm.pacman import Pacman
|
||||||
|
from ahriman.core.alpm.remote.official_syncdb import OfficialSyncdb
|
||||||
|
from ahriman.models.aur_package import AURPackage
|
||||||
|
|
||||||
|
|
||||||
|
def test_package_info(official_syncdb: OfficialSyncdb, aur_package_akonadi: AURPackage,
|
||||||
|
pacman: Pacman, mocker: MockerFixture) -> None:
|
||||||
|
"""
|
||||||
|
must return package info from the database
|
||||||
|
"""
|
||||||
|
mocker.patch("ahriman.models.aur_package.AURPackage.from_pacman", return_value=aur_package_akonadi)
|
||||||
|
get_mock = mocker.patch("ahriman.core.alpm.pacman.Pacman.get", return_value=[aur_package_akonadi])
|
||||||
|
|
||||||
|
package = official_syncdb.package_info(aur_package_akonadi.name, pacman=pacman)
|
||||||
|
get_mock.assert_called_once_with(aur_package_akonadi.name)
|
||||||
|
assert package == aur_package_akonadi
|
@ -3,70 +3,87 @@ import pytest
|
|||||||
from pytest_mock import MockerFixture
|
from pytest_mock import MockerFixture
|
||||||
from unittest import mock
|
from unittest import mock
|
||||||
|
|
||||||
|
from ahriman.core.alpm.pacman import Pacman
|
||||||
from ahriman.core.alpm.remote.remote import Remote
|
from ahriman.core.alpm.remote.remote import Remote
|
||||||
from ahriman.models.aur_package import AURPackage
|
from ahriman.models.aur_package import AURPackage
|
||||||
|
|
||||||
|
|
||||||
def test_info(mocker: MockerFixture) -> None:
|
def test_info(pacman: Pacman, mocker: MockerFixture) -> None:
|
||||||
"""
|
"""
|
||||||
must call info method
|
must call info method
|
||||||
"""
|
"""
|
||||||
info_mock = mocker.patch("ahriman.core.alpm.remote.remote.Remote.package_info")
|
info_mock = mocker.patch("ahriman.core.alpm.remote.remote.Remote.package_info")
|
||||||
Remote.info("ahriman")
|
Remote.info("ahriman", pacman=pacman)
|
||||||
info_mock.assert_called_once_with("ahriman")
|
info_mock.assert_called_once_with("ahriman", pacman=pacman)
|
||||||
|
|
||||||
|
|
||||||
def test_multisearch(aur_package_ahriman: AURPackage, mocker: MockerFixture) -> None:
|
def test_multisearch(aur_package_ahriman: AURPackage, pacman: Pacman, mocker: MockerFixture) -> None:
|
||||||
"""
|
"""
|
||||||
must search in AUR with multiple words
|
must search in AUR with multiple words
|
||||||
"""
|
"""
|
||||||
terms = ["ahriman", "is", "cool"]
|
terms = ["ahriman", "is", "cool"]
|
||||||
search_mock = mocker.patch("ahriman.core.alpm.remote.remote.Remote.search", return_value=[aur_package_ahriman])
|
search_mock = mocker.patch("ahriman.core.alpm.remote.remote.Remote.search", return_value=[aur_package_ahriman])
|
||||||
|
|
||||||
assert Remote.multisearch(*terms) == [aur_package_ahriman]
|
assert Remote.multisearch(*terms, pacman=pacman) == [aur_package_ahriman]
|
||||||
search_mock.assert_has_calls([mock.call("ahriman"), mock.call("cool")])
|
search_mock.assert_has_calls([mock.call("ahriman", pacman=pacman), mock.call("cool", pacman=pacman)])
|
||||||
|
|
||||||
|
|
||||||
def test_multisearch_empty(mocker: MockerFixture) -> None:
|
def test_multisearch_empty(pacman: Pacman, mocker: MockerFixture) -> None:
|
||||||
"""
|
"""
|
||||||
must return empty list if no long terms supplied
|
must return empty list if no long terms supplied
|
||||||
"""
|
"""
|
||||||
terms = ["it", "is"]
|
terms = ["it", "is"]
|
||||||
search_mock = mocker.patch("ahriman.core.alpm.remote.remote.Remote.search")
|
search_mock = mocker.patch("ahriman.core.alpm.remote.remote.Remote.search")
|
||||||
|
|
||||||
assert Remote.multisearch(*terms) == []
|
assert Remote.multisearch(*terms, pacman=pacman) == []
|
||||||
search_mock.assert_not_called()
|
search_mock.assert_not_called()
|
||||||
|
|
||||||
|
|
||||||
def test_multisearch_single(aur_package_ahriman: AURPackage, mocker: MockerFixture) -> None:
|
def test_multisearch_single(aur_package_ahriman: AURPackage, pacman: Pacman, mocker: MockerFixture) -> None:
|
||||||
"""
|
"""
|
||||||
must search in AUR with one word
|
must search in AUR with one word
|
||||||
"""
|
"""
|
||||||
search_mock = mocker.patch("ahriman.core.alpm.remote.remote.Remote.search", return_value=[aur_package_ahriman])
|
search_mock = mocker.patch("ahriman.core.alpm.remote.remote.Remote.search", return_value=[aur_package_ahriman])
|
||||||
assert Remote.multisearch("ahriman") == [aur_package_ahriman]
|
assert Remote.multisearch("ahriman", pacman=pacman) == [aur_package_ahriman]
|
||||||
search_mock.assert_called_once_with("ahriman")
|
search_mock.assert_called_once_with("ahriman", pacman=pacman)
|
||||||
|
|
||||||
|
|
||||||
def test_search(mocker: MockerFixture) -> None:
|
def test_remote_git_url(remote: Remote, pacman: Pacman) -> None:
|
||||||
|
"""
|
||||||
|
must raise NotImplemented for missing remote git url
|
||||||
|
"""
|
||||||
|
with pytest.raises(NotImplementedError):
|
||||||
|
remote.remote_git_url("package", "repositorys")
|
||||||
|
|
||||||
|
|
||||||
|
def test_remote_web_url(remote: Remote, pacman: Pacman) -> None:
|
||||||
|
"""
|
||||||
|
must raise NotImplemented for missing remote web url
|
||||||
|
"""
|
||||||
|
with pytest.raises(NotImplementedError):
|
||||||
|
remote.remote_web_url("package")
|
||||||
|
|
||||||
|
|
||||||
|
def test_search(pacman: Pacman, mocker: MockerFixture) -> None:
|
||||||
"""
|
"""
|
||||||
must call search method
|
must call search method
|
||||||
"""
|
"""
|
||||||
search_mock = mocker.patch("ahriman.core.alpm.remote.remote.Remote.package_search")
|
search_mock = mocker.patch("ahriman.core.alpm.remote.remote.Remote.package_search")
|
||||||
Remote.search("ahriman")
|
Remote.search("ahriman", pacman=pacman)
|
||||||
search_mock.assert_called_once_with("ahriman")
|
search_mock.assert_called_once_with("ahriman", pacman=pacman)
|
||||||
|
|
||||||
|
|
||||||
def test_package_info(remote: Remote) -> None:
|
def test_package_info(remote: Remote, pacman: Pacman) -> None:
|
||||||
"""
|
"""
|
||||||
must raise NotImplemented for missing package info method
|
must raise NotImplemented for missing package info method
|
||||||
"""
|
"""
|
||||||
with pytest.raises(NotImplementedError):
|
with pytest.raises(NotImplementedError):
|
||||||
remote.package_info("package")
|
remote.package_info("package", pacman=pacman)
|
||||||
|
|
||||||
|
|
||||||
def test_package_search(remote: Remote) -> None:
|
def test_package_search(remote: Remote, pacman: Pacman) -> None:
|
||||||
"""
|
"""
|
||||||
must raise NotImplemented for missing package search method
|
must raise NotImplemented for missing package search method
|
||||||
"""
|
"""
|
||||||
with pytest.raises(NotImplementedError):
|
with pytest.raises(NotImplementedError):
|
||||||
remote.package_search("package")
|
remote.package_search("package", pacman=pacman)
|
||||||
|
@ -15,3 +15,17 @@ def test_all_packages_with_provides(pacman: Pacman) -> None:
|
|||||||
package list must contain provides packages
|
package list must contain provides packages
|
||||||
"""
|
"""
|
||||||
assert "sh" in pacman.all_packages()
|
assert "sh" in pacman.all_packages()
|
||||||
|
|
||||||
|
|
||||||
|
def test_get(pacman: Pacman) -> None:
|
||||||
|
"""
|
||||||
|
must retrieve package
|
||||||
|
"""
|
||||||
|
assert list(pacman.get("pacman"))
|
||||||
|
|
||||||
|
|
||||||
|
def test_get_empty(pacman: Pacman) -> None:
|
||||||
|
"""
|
||||||
|
must return empty packages list without exception
|
||||||
|
"""
|
||||||
|
assert not list(pacman.get("some-random-name"))
|
||||||
|
@ -5,6 +5,7 @@ from pytest_mock import MockerFixture
|
|||||||
from unittest import mock
|
from unittest import mock
|
||||||
|
|
||||||
from ahriman.core.build_tools.sources import Sources
|
from ahriman.core.build_tools.sources import Sources
|
||||||
|
from ahriman.models.remote_source import RemoteSource
|
||||||
|
|
||||||
|
|
||||||
def test_add(mocker: MockerFixture) -> None:
|
def test_add(mocker: MockerFixture) -> None:
|
||||||
@ -45,7 +46,7 @@ def test_diff(mocker: MockerFixture) -> None:
|
|||||||
exception=None, cwd=local, logger=pytest.helpers.anyvar(int))
|
exception=None, cwd=local, logger=pytest.helpers.anyvar(int))
|
||||||
|
|
||||||
|
|
||||||
def test_fetch_empty(mocker: MockerFixture) -> None:
|
def test_fetch_empty(remote_source: RemoteSource, mocker: MockerFixture) -> None:
|
||||||
"""
|
"""
|
||||||
must do nothing in case if no branches available
|
must do nothing in case if no branches available
|
||||||
"""
|
"""
|
||||||
@ -53,46 +54,51 @@ def test_fetch_empty(mocker: MockerFixture) -> None:
|
|||||||
mocker.patch("ahriman.core.build_tools.sources.Sources.has_remotes", return_value=False)
|
mocker.patch("ahriman.core.build_tools.sources.Sources.has_remotes", return_value=False)
|
||||||
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")
|
||||||
|
|
||||||
Sources.fetch(Path("local"), "remote")
|
Sources.fetch(Path("local"), remote_source)
|
||||||
check_output_mock.assert_not_called()
|
check_output_mock.assert_not_called()
|
||||||
|
|
||||||
|
|
||||||
def test_fetch_existing(mocker: MockerFixture) -> None:
|
def test_fetch_existing(remote_source: RemoteSource, mocker: MockerFixture) -> None:
|
||||||
"""
|
"""
|
||||||
must fetch new package via fetch command
|
must fetch new package via fetch command
|
||||||
"""
|
"""
|
||||||
mocker.patch("pathlib.Path.is_dir", return_value=True)
|
mocker.patch("pathlib.Path.is_dir", return_value=True)
|
||||||
mocker.patch("ahriman.core.build_tools.sources.Sources.has_remotes", return_value=True)
|
mocker.patch("ahriman.core.build_tools.sources.Sources.has_remotes", return_value=True)
|
||||||
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")
|
||||||
|
move_mock = mocker.patch("ahriman.core.build_tools.sources.Sources.move")
|
||||||
|
|
||||||
local = Path("local")
|
local = Path("local")
|
||||||
Sources.fetch(local, "remote")
|
Sources.fetch(local, remote_source)
|
||||||
check_output_mock.assert_has_calls([
|
check_output_mock.assert_has_calls([
|
||||||
mock.call("git", "fetch", "origin", Sources._branch,
|
mock.call("git", "fetch", "origin", remote_source.branch,
|
||||||
exception=None, cwd=local, logger=pytest.helpers.anyvar(int)),
|
exception=None, cwd=local, logger=pytest.helpers.anyvar(int)),
|
||||||
mock.call("git", "checkout", "--force", Sources._branch,
|
mock.call("git", "checkout", "--force", remote_source.branch,
|
||||||
exception=None, cwd=local, logger=pytest.helpers.anyvar(int)),
|
exception=None, cwd=local, logger=pytest.helpers.anyvar(int)),
|
||||||
mock.call("git", "reset", "--hard", f"origin/{Sources._branch}",
|
mock.call("git", "reset", "--hard", f"origin/{remote_source.branch}",
|
||||||
exception=None, cwd=local, logger=pytest.helpers.anyvar(int))
|
exception=None, cwd=local, logger=pytest.helpers.anyvar(int))
|
||||||
])
|
])
|
||||||
|
move_mock.assert_called_once_with(local.resolve(), local)
|
||||||
|
|
||||||
|
|
||||||
def test_fetch_new(mocker: MockerFixture) -> None:
|
def test_fetch_new(remote_source: RemoteSource, mocker: MockerFixture) -> None:
|
||||||
"""
|
"""
|
||||||
must fetch new package via clone command
|
must fetch new package via clone command
|
||||||
"""
|
"""
|
||||||
mocker.patch("pathlib.Path.is_dir", return_value=False)
|
mocker.patch("pathlib.Path.is_dir", return_value=False)
|
||||||
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")
|
||||||
|
move_mock = mocker.patch("ahriman.core.build_tools.sources.Sources.move")
|
||||||
|
|
||||||
local = Path("local")
|
local = Path("local")
|
||||||
Sources.fetch(local, "remote")
|
Sources.fetch(local, remote_source)
|
||||||
check_output_mock.assert_has_calls([
|
check_output_mock.assert_has_calls([
|
||||||
mock.call("git", "clone", "remote", str(local), exception=None, cwd=local, logger=pytest.helpers.anyvar(int)),
|
mock.call("git", "clone", "--branch", remote_source.branch, "--single-branch",
|
||||||
mock.call("git", "checkout", "--force", Sources._branch,
|
remote_source.git_url, str(local), exception=None, cwd=local, logger=pytest.helpers.anyvar(int)),
|
||||||
|
mock.call("git", "checkout", "--force", remote_source.branch,
|
||||||
exception=None, cwd=local, logger=pytest.helpers.anyvar(int)),
|
exception=None, cwd=local, logger=pytest.helpers.anyvar(int)),
|
||||||
mock.call("git", "reset", "--hard", f"origin/{Sources._branch}",
|
mock.call("git", "reset", "--hard", f"origin/{remote_source.branch}",
|
||||||
exception=None, cwd=local, logger=pytest.helpers.anyvar(int))
|
exception=None, cwd=local, logger=pytest.helpers.anyvar(int))
|
||||||
])
|
])
|
||||||
|
move_mock.assert_called_once_with(local.resolve(), local)
|
||||||
|
|
||||||
|
|
||||||
def test_fetch_new_without_remote(mocker: MockerFixture) -> None:
|
def test_fetch_new_without_remote(mocker: MockerFixture) -> None:
|
||||||
@ -101,15 +107,28 @@ def test_fetch_new_without_remote(mocker: MockerFixture) -> None:
|
|||||||
"""
|
"""
|
||||||
mocker.patch("pathlib.Path.is_dir", return_value=False)
|
mocker.patch("pathlib.Path.is_dir", return_value=False)
|
||||||
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")
|
||||||
|
move_mock = mocker.patch("ahriman.core.build_tools.sources.Sources.move")
|
||||||
|
|
||||||
local = Path("local")
|
local = Path("local")
|
||||||
Sources.fetch(local, None)
|
Sources.fetch(local, None)
|
||||||
check_output_mock.assert_has_calls([
|
check_output_mock.assert_has_calls([
|
||||||
mock.call("git", "checkout", "--force", Sources._branch,
|
mock.call("git", "checkout", "--force", Sources.DEFAULT_BRANCH,
|
||||||
exception=None, cwd=local, logger=pytest.helpers.anyvar(int)),
|
exception=None, cwd=local, logger=pytest.helpers.anyvar(int)),
|
||||||
mock.call("git", "reset", "--hard", f"origin/{Sources._branch}",
|
mock.call("git", "reset", "--hard", f"origin/{Sources.DEFAULT_BRANCH}",
|
||||||
exception=None, cwd=local, logger=pytest.helpers.anyvar(int))
|
exception=None, cwd=local, logger=pytest.helpers.anyvar(int))
|
||||||
])
|
])
|
||||||
|
move_mock.assert_called_once_with(local.resolve(), local)
|
||||||
|
|
||||||
|
|
||||||
|
def test_fetch_relative(remote_source: RemoteSource, mocker: MockerFixture) -> None:
|
||||||
|
"""
|
||||||
|
must process move correctly on relative directory
|
||||||
|
"""
|
||||||
|
mocker.patch("ahriman.core.build_tools.sources.Sources._check_output")
|
||||||
|
move_mock = mocker.patch("ahriman.core.build_tools.sources.Sources.move")
|
||||||
|
|
||||||
|
Sources.fetch(Path("path"), remote_source)
|
||||||
|
move_mock.assert_called_once_with(Path("path").resolve(), Path("path"))
|
||||||
|
|
||||||
|
|
||||||
def test_has_remotes(mocker: MockerFixture) -> None:
|
def test_has_remotes(mocker: MockerFixture) -> None:
|
||||||
@ -140,33 +159,53 @@ def test_init(mocker: MockerFixture) -> None:
|
|||||||
|
|
||||||
local = Path("local")
|
local = Path("local")
|
||||||
Sources.init(local)
|
Sources.init(local)
|
||||||
check_output_mock.assert_called_once_with("git", "init", "--initial-branch", Sources._branch,
|
check_output_mock.assert_called_once_with("git", "init", "--initial-branch", Sources.DEFAULT_BRANCH,
|
||||||
exception=None, cwd=local, logger=pytest.helpers.anyvar(int))
|
exception=None, cwd=local, logger=pytest.helpers.anyvar(int))
|
||||||
|
|
||||||
|
|
||||||
def test_load(mocker: MockerFixture) -> None:
|
def test_load(remote_source: RemoteSource, mocker: MockerFixture) -> None:
|
||||||
"""
|
"""
|
||||||
must load packages sources correctly
|
must load packages sources correctly
|
||||||
"""
|
"""
|
||||||
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")
|
||||||
|
|
||||||
Sources.load(Path("local"), "remote", "patch")
|
Sources.load(Path("local"), remote_source, "patch")
|
||||||
fetch_mock.assert_called_once_with(Path("local"), "remote")
|
fetch_mock.assert_called_once_with(Path("local"), remote_source)
|
||||||
patch_mock.assert_called_once_with(Path("local"), "patch")
|
patch_mock.assert_called_once_with(Path("local"), "patch")
|
||||||
|
|
||||||
|
|
||||||
def test_load_no_patch(mocker: MockerFixture) -> None:
|
def test_load_no_patch(remote_source: RemoteSource, mocker: MockerFixture) -> None:
|
||||||
"""
|
"""
|
||||||
must load packages sources correctly without patches
|
must load packages sources correctly without patches
|
||||||
"""
|
"""
|
||||||
mocker.patch("ahriman.core.build_tools.sources.Sources.fetch")
|
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")
|
||||||
|
|
||||||
Sources.load(Path("local"), "remote", None)
|
Sources.load(Path("local"), remote_source, None)
|
||||||
patch_mock.assert_not_called()
|
patch_mock.assert_not_called()
|
||||||
|
|
||||||
|
|
||||||
|
def test_move(mocker: MockerFixture) -> None:
|
||||||
|
"""
|
||||||
|
must move content between directories
|
||||||
|
"""
|
||||||
|
mocker.patch("ahriman.core.build_tools.sources.walk", return_value=[Path("/source/path")])
|
||||||
|
move_mock = mocker.patch("shutil.move")
|
||||||
|
|
||||||
|
Sources.move(Path("/source"), Path("/destination"))
|
||||||
|
move_mock.assert_called_once_with(Path("/source/path"), Path("/destination/path"))
|
||||||
|
|
||||||
|
|
||||||
|
def test_move_same(mocker: MockerFixture) -> None:
|
||||||
|
"""
|
||||||
|
must not do anything in case if directories are the same
|
||||||
|
"""
|
||||||
|
walk_mock = mocker.patch("ahriman.core.build_tools.sources.walk")
|
||||||
|
Sources.move(Path("/same"), Path("/same"))
|
||||||
|
walk_mock.assert_not_called()
|
||||||
|
|
||||||
|
|
||||||
def test_patch_apply(mocker: MockerFixture) -> None:
|
def test_patch_apply(mocker: MockerFixture) -> None:
|
||||||
"""
|
"""
|
||||||
must apply patches if any
|
must apply patches if any
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from ahriman.core.alpm.pacman import Pacman
|
|
||||||
from ahriman.core.alpm.repo import Repo
|
from ahriman.core.alpm.repo import Repo
|
||||||
from ahriman.core.build_tools.task import Task
|
from ahriman.core.build_tools.task import Task
|
||||||
from ahriman.core.configuration import Configuration
|
from ahriman.core.configuration import Configuration
|
||||||
@ -37,20 +36,6 @@ def leaf_python_schedule(package_python_schedule: Package) -> Leaf:
|
|||||||
return Leaf(package_python_schedule, set())
|
return Leaf(package_python_schedule, set())
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
|
||||||
def pacman(configuration: Configuration) -> Pacman:
|
|
||||||
"""
|
|
||||||
fixture for pacman wrapper
|
|
||||||
|
|
||||||
Args:
|
|
||||||
configuration(Configuration): configuration fixture
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
Pacman: pacman wrapper test instance
|
|
||||||
"""
|
|
||||||
return Pacman(configuration)
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def repo(configuration: Configuration, repository_paths: RepositoryPaths) -> Repo:
|
def repo(configuration: Configuration, repository_paths: RepositoryPaths) -> Repo:
|
||||||
"""
|
"""
|
||||||
|
@ -15,11 +15,24 @@ def test_migrate_data_initial(connection: Connection, configuration: Configurati
|
|||||||
packages = mocker.patch("ahriman.core.database.data.migrate_package_statuses")
|
packages = mocker.patch("ahriman.core.database.data.migrate_package_statuses")
|
||||||
patches = mocker.patch("ahriman.core.database.data.migrate_patches")
|
patches = mocker.patch("ahriman.core.database.data.migrate_patches")
|
||||||
users = mocker.patch("ahriman.core.database.data.migrate_users_data")
|
users = mocker.patch("ahriman.core.database.data.migrate_users_data")
|
||||||
|
remotes = mocker.patch("ahriman.core.database.data.migrate_package_remotes")
|
||||||
|
|
||||||
migrate_data(MigrationResult(old_version=0, new_version=900), connection, configuration)
|
migrate_data(MigrationResult(old_version=0, new_version=900), connection, configuration)
|
||||||
packages.assert_called_once_with(connection, repository_paths)
|
packages.assert_called_once_with(connection, repository_paths)
|
||||||
patches.assert_called_once_with(connection, repository_paths)
|
patches.assert_called_once_with(connection, repository_paths)
|
||||||
users.assert_called_once_with(connection, configuration)
|
users.assert_called_once_with(connection, configuration)
|
||||||
|
remotes.assert_called_once_with(connection, repository_paths)
|
||||||
|
|
||||||
|
|
||||||
|
def test_migrate_data_remotes(connection: Connection, configuration: Configuration,
|
||||||
|
repository_paths: RepositoryPaths, mocker: MockerFixture) -> None:
|
||||||
|
"""
|
||||||
|
must perform initial migration
|
||||||
|
"""
|
||||||
|
remotes = mocker.patch("ahriman.core.database.data.migrate_package_remotes")
|
||||||
|
|
||||||
|
migrate_data(MigrationResult(old_version=1, new_version=900), connection, configuration)
|
||||||
|
remotes.assert_called_once_with(connection, repository_paths)
|
||||||
|
|
||||||
|
|
||||||
def test_migrate_data_skip(connection: Connection, configuration: Configuration, mocker: MockerFixture) -> None:
|
def test_migrate_data_skip(connection: Connection, configuration: Configuration, mocker: MockerFixture) -> None:
|
||||||
|
66
tests/ahriman/core/database/data/test_package_remotes.py
Normal file
66
tests/ahriman/core/database/data/test_package_remotes.py
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
import pytest
|
||||||
|
|
||||||
|
from pytest_mock import MockerFixture
|
||||||
|
from sqlite3 import Connection
|
||||||
|
|
||||||
|
from ahriman.core.database.data import migrate_package_remotes
|
||||||
|
from ahriman.models.package import Package
|
||||||
|
from ahriman.models.repository_paths import RepositoryPaths
|
||||||
|
|
||||||
|
|
||||||
|
def test_migrate_package_remotes(package_ahriman: Package, connection: Connection, repository_paths: RepositoryPaths,
|
||||||
|
mocker: MockerFixture) -> None:
|
||||||
|
"""
|
||||||
|
must put package remotes to database
|
||||||
|
"""
|
||||||
|
mocker.patch(
|
||||||
|
"ahriman.core.database.operations.package_operations.PackageOperations._packages_get_select_package_bases",
|
||||||
|
return_value={package_ahriman.base: package_ahriman})
|
||||||
|
mocker.patch("pathlib.Path.exists", return_value=False)
|
||||||
|
|
||||||
|
migrate_package_remotes(connection, repository_paths)
|
||||||
|
connection.execute.assert_called_once_with(pytest.helpers.anyvar(str, strict=True), pytest.helpers.anyvar(int))
|
||||||
|
|
||||||
|
|
||||||
|
def test_migrate_package_remotes_has_local(package_ahriman: Package, connection: Connection,
|
||||||
|
repository_paths: RepositoryPaths, mocker: MockerFixture) -> None:
|
||||||
|
"""
|
||||||
|
must skip processing for packages which have local cache
|
||||||
|
"""
|
||||||
|
mocker.patch(
|
||||||
|
"ahriman.core.database.operations.package_operations.PackageOperations._packages_get_select_package_bases",
|
||||||
|
return_value={package_ahriman.base: package_ahriman})
|
||||||
|
mocker.patch("pathlib.Path.exists", return_value=True)
|
||||||
|
|
||||||
|
migrate_package_remotes(connection, repository_paths)
|
||||||
|
connection.execute.assert_not_called()
|
||||||
|
|
||||||
|
|
||||||
|
def test_migrate_package_remotes_vcs(package_ahriman: Package, connection: Connection,
|
||||||
|
repository_paths: RepositoryPaths, mocker: MockerFixture) -> None:
|
||||||
|
"""
|
||||||
|
must process VCS packages with local cache
|
||||||
|
"""
|
||||||
|
mocker.patch(
|
||||||
|
"ahriman.core.database.operations.package_operations.PackageOperations._packages_get_select_package_bases",
|
||||||
|
return_value={package_ahriman.base: package_ahriman})
|
||||||
|
mocker.patch("pathlib.Path.exists", return_value=True)
|
||||||
|
mocker.patch.object(Package, "is_vcs", True)
|
||||||
|
|
||||||
|
migrate_package_remotes(connection, repository_paths)
|
||||||
|
connection.execute.assert_called_once_with(pytest.helpers.anyvar(str, strict=True), pytest.helpers.anyvar(int))
|
||||||
|
|
||||||
|
|
||||||
|
def test_migrate_package_remotes_no_remotes(package_ahriman: Package, connection: Connection,
|
||||||
|
repository_paths: RepositoryPaths, mocker: MockerFixture) -> None:
|
||||||
|
"""
|
||||||
|
must skip processing in case if no remotes generated (should never happen)
|
||||||
|
"""
|
||||||
|
mocker.patch(
|
||||||
|
"ahriman.core.database.operations.package_operations.PackageOperations._packages_get_select_package_bases",
|
||||||
|
return_value={package_ahriman.base: package_ahriman})
|
||||||
|
mocker.patch("pathlib.Path.exists", return_value=False)
|
||||||
|
mocker.patch("ahriman.models.remote_source.RemoteSource.from_remote", return_value=None)
|
||||||
|
|
||||||
|
migrate_package_remotes(connection, repository_paths)
|
||||||
|
connection.execute.assert_not_called()
|
@ -9,7 +9,7 @@ from ahriman.core.database.data import migrate_users_data
|
|||||||
|
|
||||||
def test_migrate_users_data(connection: Connection, configuration: Configuration) -> None:
|
def test_migrate_users_data(connection: Connection, configuration: Configuration) -> None:
|
||||||
"""
|
"""
|
||||||
must users to database
|
must put users to database
|
||||||
"""
|
"""
|
||||||
configuration.set_option("auth:read", "user1", "password1")
|
configuration.set_option("auth:read", "user1", "password1")
|
||||||
configuration.set_option("auth:write", "user2", "password2")
|
configuration.set_option("auth:write", "user2", "password2")
|
||||||
|
@ -0,0 +1,8 @@
|
|||||||
|
from ahriman.core.database.migrations.m001_package_source import steps
|
||||||
|
|
||||||
|
|
||||||
|
def test_migration_package_source() -> None:
|
||||||
|
"""
|
||||||
|
migration must not be empty
|
||||||
|
"""
|
||||||
|
assert steps
|
@ -7,6 +7,8 @@ from unittest import mock
|
|||||||
from ahriman.core.database.sqlite import SQLite
|
from ahriman.core.database.sqlite import SQLite
|
||||||
from ahriman.models.build_status import BuildStatus, BuildStatusEnum
|
from ahriman.models.build_status import BuildStatus, BuildStatusEnum
|
||||||
from ahriman.models.package import Package
|
from ahriman.models.package import Package
|
||||||
|
from ahriman.models.package_source import PackageSource
|
||||||
|
from ahriman.models.remote_source import RemoteSource
|
||||||
|
|
||||||
|
|
||||||
def test_package_remove_package_base(database: SQLite, connection: Connection) -> None:
|
def test_package_remove_package_base(database: SQLite, connection: Connection) -> None:
|
||||||
@ -166,3 +168,23 @@ def test_package_update_update(database: SQLite, package_ahriman: Package) -> No
|
|||||||
assert next(db_status.status
|
assert next(db_status.status
|
||||||
for db_package, db_status in database.packages_get()
|
for db_package, db_status in database.packages_get()
|
||||||
if db_package.base == package_ahriman.base) == BuildStatusEnum.Failed
|
if db_package.base == package_ahriman.base) == BuildStatusEnum.Failed
|
||||||
|
|
||||||
|
|
||||||
|
def test_remote_update_get(database: SQLite, package_ahriman: Package) -> None:
|
||||||
|
"""
|
||||||
|
must insert and retrieve package remote
|
||||||
|
"""
|
||||||
|
database.remote_update(package_ahriman)
|
||||||
|
assert database.remotes_get()[package_ahriman.base] == package_ahriman.remote
|
||||||
|
|
||||||
|
|
||||||
|
def test_remote_update_update(database: SQLite, package_ahriman: Package) -> None:
|
||||||
|
"""
|
||||||
|
must perform package remote update for existing package
|
||||||
|
"""
|
||||||
|
database.remote_update(package_ahriman)
|
||||||
|
remote_source = RemoteSource.from_remote(PackageSource.Repository, package_ahriman.base, "community")
|
||||||
|
package_ahriman.remote = remote_source
|
||||||
|
|
||||||
|
database.remote_update(package_ahriman)
|
||||||
|
assert database.remotes_get()[package_ahriman.base] == remote_source
|
||||||
|
@ -15,11 +15,11 @@ def test_load_archives(package_ahriman: Package, package_python_schedule: Packag
|
|||||||
single_packages = [
|
single_packages = [
|
||||||
Package(base=package_python_schedule.base,
|
Package(base=package_python_schedule.base,
|
||||||
version=package_python_schedule.version,
|
version=package_python_schedule.version,
|
||||||
aur_url=package_python_schedule.aur_url,
|
remote=package_python_schedule.remote,
|
||||||
packages={package: props})
|
packages={package: props})
|
||||||
for package, props in package_python_schedule.packages.items()
|
for package, props in package_python_schedule.packages.items()
|
||||||
] + [package_ahriman]
|
] + [package_ahriman]
|
||||||
mocker.patch("ahriman.models.package.Package.load", side_effect=single_packages)
|
mocker.patch("ahriman.models.package.Package.from_archive", side_effect=single_packages)
|
||||||
|
|
||||||
packages = repository.load_archives([Path("a.pkg.tar.xz"), Path("b.pkg.tar.xz"), Path("c.pkg.tar.xz")])
|
packages = repository.load_archives([Path("a.pkg.tar.xz"), Path("b.pkg.tar.xz"), Path("c.pkg.tar.xz")])
|
||||||
assert len(packages) == 2
|
assert len(packages) == 2
|
||||||
@ -36,7 +36,7 @@ def test_load_archives_failed(repository: Repository, mocker: MockerFixture) ->
|
|||||||
"""
|
"""
|
||||||
must skip packages which cannot be loaded
|
must skip packages which cannot be loaded
|
||||||
"""
|
"""
|
||||||
mocker.patch("ahriman.models.package.Package.load", side_effect=Exception())
|
mocker.patch("ahriman.models.package.Package.from_archive", side_effect=Exception())
|
||||||
assert not repository.load_archives([Path("a.pkg.tar.xz")])
|
assert not repository.load_archives([Path("a.pkg.tar.xz")])
|
||||||
|
|
||||||
|
|
||||||
@ -55,12 +55,12 @@ def test_load_archives_different_version(repository: Repository, package_python_
|
|||||||
single_packages = [
|
single_packages = [
|
||||||
Package(base=package_python_schedule.base,
|
Package(base=package_python_schedule.base,
|
||||||
version=package_python_schedule.version,
|
version=package_python_schedule.version,
|
||||||
aur_url=package_python_schedule.aur_url,
|
remote=package_python_schedule.remote,
|
||||||
packages={package: props})
|
packages={package: props})
|
||||||
for package, props in package_python_schedule.packages.items()
|
for package, props in package_python_schedule.packages.items()
|
||||||
]
|
]
|
||||||
single_packages[0].version = "0.0.1-1"
|
single_packages[0].version = "0.0.1-1"
|
||||||
mocker.patch("ahriman.models.package.Package.load", side_effect=single_packages)
|
mocker.patch("ahriman.models.package.Package.from_archive", side_effect=single_packages)
|
||||||
|
|
||||||
packages = repository.load_archives([Path("a.pkg.tar.xz"), Path("b.pkg.tar.xz")])
|
packages = repository.load_archives([Path("a.pkg.tar.xz"), Path("b.pkg.tar.xz")])
|
||||||
assert len(packages) == 1
|
assert len(packages) == 1
|
||||||
|
@ -5,6 +5,7 @@ from pytest_mock import MockerFixture
|
|||||||
from ahriman.core.repository.update_handler import UpdateHandler
|
from ahriman.core.repository.update_handler import UpdateHandler
|
||||||
from ahriman.models.package import Package
|
from ahriman.models.package import Package
|
||||||
from ahriman.models.package_source import PackageSource
|
from ahriman.models.package_source import PackageSource
|
||||||
|
from ahriman.models.remote_source import RemoteSource
|
||||||
|
|
||||||
|
|
||||||
def test_packages(update_handler: UpdateHandler) -> None:
|
def test_packages(update_handler: UpdateHandler) -> None:
|
||||||
@ -22,7 +23,22 @@ def test_updates_aur(update_handler: UpdateHandler, package_ahriman: Package,
|
|||||||
"""
|
"""
|
||||||
mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.packages", return_value=[package_ahriman])
|
mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.packages", return_value=[package_ahriman])
|
||||||
mocker.patch("ahriman.models.package.Package.is_outdated", return_value=True)
|
mocker.patch("ahriman.models.package.Package.is_outdated", return_value=True)
|
||||||
mocker.patch("ahriman.models.package.Package.load", return_value=package_ahriman)
|
mocker.patch("ahriman.models.package.Package.from_aur", return_value=package_ahriman)
|
||||||
|
status_client_mock = mocker.patch("ahriman.core.status.client.Client.set_pending")
|
||||||
|
|
||||||
|
assert update_handler.updates_aur([], False) == [package_ahriman]
|
||||||
|
status_client_mock.assert_called_once_with(package_ahriman.base)
|
||||||
|
|
||||||
|
|
||||||
|
def test_updates_aur_official(update_handler: UpdateHandler, package_ahriman: Package,
|
||||||
|
mocker: MockerFixture) -> None:
|
||||||
|
"""
|
||||||
|
must provide updates based on repository data
|
||||||
|
"""
|
||||||
|
package_ahriman.remote = RemoteSource.from_remote(PackageSource.Repository, package_ahriman.base, "community")
|
||||||
|
mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.packages", return_value=[package_ahriman])
|
||||||
|
mocker.patch("ahriman.models.package.Package.is_outdated", return_value=True)
|
||||||
|
mocker.patch("ahriman.models.package.Package.from_official", return_value=package_ahriman)
|
||||||
status_client_mock = mocker.patch("ahriman.core.status.client.Client.set_pending")
|
status_client_mock = mocker.patch("ahriman.core.status.client.Client.set_pending")
|
||||||
|
|
||||||
assert update_handler.updates_aur([], False) == [package_ahriman]
|
assert update_handler.updates_aur([], False) == [package_ahriman]
|
||||||
@ -36,7 +52,7 @@ def test_updates_aur_success(update_handler: UpdateHandler, package_ahriman: Pac
|
|||||||
"""
|
"""
|
||||||
mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.packages", return_value=[package_ahriman])
|
mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.packages", return_value=[package_ahriman])
|
||||||
mocker.patch("ahriman.models.package.Package.is_outdated", return_value=False)
|
mocker.patch("ahriman.models.package.Package.is_outdated", return_value=False)
|
||||||
mocker.patch("ahriman.models.package.Package.load", return_value=package_ahriman)
|
mocker.patch("ahriman.models.package.Package.from_aur", return_value=package_ahriman)
|
||||||
status_client_mock = mocker.patch("ahriman.core.status.client.Client.set_success")
|
status_client_mock = mocker.patch("ahriman.core.status.client.Client.set_success")
|
||||||
|
|
||||||
assert not update_handler.updates_aur([], False)
|
assert not update_handler.updates_aur([], False)
|
||||||
@ -49,7 +65,7 @@ def test_updates_aur_failed(update_handler: UpdateHandler, package_ahriman: Pack
|
|||||||
must update status via client for failed load
|
must update status via client for failed load
|
||||||
"""
|
"""
|
||||||
mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.packages", return_value=[package_ahriman])
|
mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.packages", return_value=[package_ahriman])
|
||||||
mocker.patch("ahriman.models.package.Package.load", side_effect=Exception())
|
mocker.patch("ahriman.models.package.Package.from_aur", side_effect=Exception())
|
||||||
status_client_mock = mocker.patch("ahriman.core.status.client.Client.set_failed")
|
status_client_mock = mocker.patch("ahriman.core.status.client.Client.set_failed")
|
||||||
|
|
||||||
update_handler.updates_aur([], False)
|
update_handler.updates_aur([], False)
|
||||||
@ -64,11 +80,10 @@ def test_updates_aur_filter(update_handler: UpdateHandler, package_ahriman: Pack
|
|||||||
mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.packages",
|
mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.packages",
|
||||||
return_value=[package_ahriman, package_python_schedule])
|
return_value=[package_ahriman, package_python_schedule])
|
||||||
mocker.patch("ahriman.models.package.Package.is_outdated", return_value=True)
|
mocker.patch("ahriman.models.package.Package.is_outdated", return_value=True)
|
||||||
package_load_mock = mocker.patch("ahriman.models.package.Package.load", return_value=package_ahriman)
|
package_load_mock = mocker.patch("ahriman.models.package.Package.from_aur", return_value=package_ahriman)
|
||||||
|
|
||||||
assert update_handler.updates_aur([package_ahriman.base], False) == [package_ahriman]
|
assert update_handler.updates_aur([package_ahriman.base], False) == [package_ahriman]
|
||||||
package_load_mock.assert_called_once_with(package_ahriman.base, PackageSource.AUR,
|
package_load_mock.assert_called_once_with(package_ahriman.base, update_handler.pacman)
|
||||||
update_handler.pacman, update_handler.aur_url)
|
|
||||||
|
|
||||||
|
|
||||||
def test_updates_aur_ignore(update_handler: UpdateHandler, package_ahriman: Package,
|
def test_updates_aur_ignore(update_handler: UpdateHandler, package_ahriman: Package,
|
||||||
@ -78,7 +93,7 @@ def test_updates_aur_ignore(update_handler: UpdateHandler, package_ahriman: Pack
|
|||||||
"""
|
"""
|
||||||
update_handler.ignore_list = [package_ahriman.base]
|
update_handler.ignore_list = [package_ahriman.base]
|
||||||
mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.packages", return_value=[package_ahriman])
|
mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.packages", return_value=[package_ahriman])
|
||||||
package_load_mock = mocker.patch("ahriman.models.package.Package.load")
|
package_load_mock = mocker.patch("ahriman.models.package.Package.from_aur")
|
||||||
|
|
||||||
update_handler.updates_aur([], False)
|
update_handler.updates_aur([], False)
|
||||||
package_load_mock.assert_not_called()
|
package_load_mock.assert_not_called()
|
||||||
@ -105,13 +120,12 @@ def test_updates_local(update_handler: UpdateHandler, package_ahriman: Package,
|
|||||||
mocker.patch("pathlib.Path.iterdir", return_value=[package_ahriman.base])
|
mocker.patch("pathlib.Path.iterdir", return_value=[package_ahriman.base])
|
||||||
mocker.patch("ahriman.models.package.Package.is_outdated", return_value=True)
|
mocker.patch("ahriman.models.package.Package.is_outdated", return_value=True)
|
||||||
fetch_mock = mocker.patch("ahriman.core.build_tools.sources.Sources.fetch")
|
fetch_mock = mocker.patch("ahriman.core.build_tools.sources.Sources.fetch")
|
||||||
package_load_mock = mocker.patch("ahriman.models.package.Package.load", return_value=package_ahriman)
|
package_load_mock = mocker.patch("ahriman.models.package.Package.from_build", return_value=package_ahriman)
|
||||||
status_client_mock = mocker.patch("ahriman.core.status.client.Client.set_pending")
|
status_client_mock = mocker.patch("ahriman.core.status.client.Client.set_pending")
|
||||||
|
|
||||||
assert update_handler.updates_local() == [package_ahriman]
|
assert update_handler.updates_local() == [package_ahriman]
|
||||||
fetch_mock.assert_called_once_with(package_ahriman.base, remote=None)
|
fetch_mock.assert_called_once_with(package_ahriman.base, remote=None)
|
||||||
package_load_mock.assert_called_once_with(
|
package_load_mock.assert_called_once_with(package_ahriman.base)
|
||||||
package_ahriman.base, PackageSource.Local, update_handler.pacman, update_handler.aur_url)
|
|
||||||
status_client_mock.assert_called_once_with(package_ahriman.base)
|
status_client_mock.assert_called_once_with(package_ahriman.base)
|
||||||
|
|
||||||
|
|
||||||
@ -123,7 +137,7 @@ def test_updates_local_unknown(update_handler: UpdateHandler, package_ahriman: P
|
|||||||
mocker.patch("pathlib.Path.iterdir", return_value=[package_ahriman.base])
|
mocker.patch("pathlib.Path.iterdir", return_value=[package_ahriman.base])
|
||||||
mocker.patch("ahriman.models.package.Package.is_outdated", return_value=True)
|
mocker.patch("ahriman.models.package.Package.is_outdated", return_value=True)
|
||||||
mocker.patch("ahriman.core.build_tools.sources.Sources.fetch")
|
mocker.patch("ahriman.core.build_tools.sources.Sources.fetch")
|
||||||
mocker.patch("ahriman.models.package.Package.load", return_value=package_ahriman)
|
mocker.patch("ahriman.models.package.Package.from_build", return_value=package_ahriman)
|
||||||
status_client_mock = mocker.patch("ahriman.core.status.client.Client.set_unknown")
|
status_client_mock = mocker.patch("ahriman.core.status.client.Client.set_unknown")
|
||||||
|
|
||||||
assert update_handler.updates_local() == [package_ahriman]
|
assert update_handler.updates_local() == [package_ahriman]
|
||||||
@ -151,7 +165,7 @@ def test_updates_local_success(update_handler: UpdateHandler, package_ahriman: P
|
|||||||
mocker.patch("pathlib.Path.iterdir", return_value=[package_ahriman.base])
|
mocker.patch("pathlib.Path.iterdir", return_value=[package_ahriman.base])
|
||||||
mocker.patch("ahriman.models.package.Package.is_outdated", return_value=False)
|
mocker.patch("ahriman.models.package.Package.is_outdated", return_value=False)
|
||||||
mocker.patch("ahriman.core.build_tools.sources.Sources.fetch")
|
mocker.patch("ahriman.core.build_tools.sources.Sources.fetch")
|
||||||
mocker.patch("ahriman.models.package.Package.load", return_value=package_ahriman)
|
mocker.patch("ahriman.models.package.Package.from_build", return_value=package_ahriman)
|
||||||
status_client_mock = mocker.patch("ahriman.core.status.client.Client.set_success")
|
status_client_mock = mocker.patch("ahriman.core.status.client.Client.set_success")
|
||||||
|
|
||||||
assert not update_handler.updates_local()
|
assert not update_handler.updates_local()
|
||||||
|
@ -51,7 +51,7 @@ def test_leaf_load(package_ahriman: Package, database: SQLite, mocker: MockerFix
|
|||||||
assert leaf.dependencies == {"ahriman-dependency"}
|
assert leaf.dependencies == {"ahriman-dependency"}
|
||||||
tempdir_mock.assert_called_once_with()
|
tempdir_mock.assert_called_once_with()
|
||||||
load_mock.assert_called_once_with(
|
load_mock.assert_called_once_with(
|
||||||
pytest.helpers.anyvar(int), package_ahriman.git_url, database.patches_get(package_ahriman.base))
|
pytest.helpers.anyvar(int), package_ahriman.remote, database.patches_get(package_ahriman.base))
|
||||||
dependencies_mock.assert_called_once_with(pytest.helpers.anyvar(int))
|
dependencies_mock.assert_called_once_with(pytest.helpers.anyvar(int))
|
||||||
rmtree_mock.assert_called_once_with(pytest.helpers.anyvar(int), ignore_errors=True)
|
rmtree_mock.assert_called_once_with(pytest.helpers.anyvar(int), ignore_errors=True)
|
||||||
|
|
||||||
|
@ -1,14 +1,18 @@
|
|||||||
|
import datetime
|
||||||
import pytest
|
import pytest
|
||||||
import time
|
import time
|
||||||
|
|
||||||
from unittest.mock import MagicMock, PropertyMock
|
from unittest.mock import MagicMock, PropertyMock
|
||||||
|
|
||||||
from ahriman import version
|
from ahriman import version
|
||||||
|
from ahriman.models.aur_package import AURPackage
|
||||||
from ahriman.models.build_status import BuildStatus, BuildStatusEnum
|
from ahriman.models.build_status import BuildStatus, BuildStatusEnum
|
||||||
from ahriman.models.counters import Counters
|
from ahriman.models.counters import Counters
|
||||||
from ahriman.models.internal_status import InternalStatus
|
from ahriman.models.internal_status import InternalStatus
|
||||||
from ahriman.models.package import Package
|
from ahriman.models.package import Package
|
||||||
from ahriman.models.package_description import PackageDescription
|
from ahriman.models.package_description import PackageDescription
|
||||||
|
from ahriman.models.package_source import PackageSource
|
||||||
|
from ahriman.models.remote_source import RemoteSource
|
||||||
from ahriman.models.user_identity import UserIdentity
|
from ahriman.models.user_identity import UserIdentity
|
||||||
|
|
||||||
|
|
||||||
@ -67,7 +71,7 @@ def package_tpacpi_bat_git() -> Package:
|
|||||||
return Package(
|
return Package(
|
||||||
base="tpacpi-bat-git",
|
base="tpacpi-bat-git",
|
||||||
version="3.1.r12.g4959b52-1",
|
version="3.1.r12.g4959b52-1",
|
||||||
aur_url="https://aur.archlinux.org",
|
remote=RemoteSource.from_remote(PackageSource.AUR, "tpacpi-bat-git", "aur"),
|
||||||
packages={"tpacpi-bat-git": PackageDescription()})
|
packages={"tpacpi-bat-git": PackageDescription()})
|
||||||
|
|
||||||
|
|
||||||
@ -88,22 +92,34 @@ def pyalpm_handle(pyalpm_package_ahriman: MagicMock) -> MagicMock:
|
|||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def pyalpm_package_ahriman(package_ahriman: Package) -> MagicMock:
|
def pyalpm_package_ahriman(aur_package_ahriman: AURPackage) -> MagicMock:
|
||||||
"""
|
"""
|
||||||
mock object for pyalpm package
|
mock object for pyalpm package
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
package_ahriman(Package): package fixture
|
aur_package_ahriman(AURPackage): package fixture
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
MagicMock: pyalpm package mock
|
MagicMock: pyalpm package mock
|
||||||
"""
|
"""
|
||||||
mock = MagicMock()
|
mock = MagicMock()
|
||||||
type(mock).base = PropertyMock(return_value=package_ahriman.base)
|
db = type(mock).db = MagicMock()
|
||||||
type(mock).depends = PropertyMock(return_value=["python-aur"])
|
|
||||||
type(mock).name = PropertyMock(return_value=package_ahriman.base)
|
type(mock).base = PropertyMock(return_value=aur_package_ahriman.package_base)
|
||||||
type(mock).provides = PropertyMock(return_value=["python-ahriman"])
|
type(mock).builddate = PropertyMock(
|
||||||
type(mock).version = PropertyMock(return_value=package_ahriman.version)
|
return_value=aur_package_ahriman.last_modified.replace(tzinfo=datetime.timezone.utc).timestamp())
|
||||||
|
type(mock).conflicts = PropertyMock(return_value=aur_package_ahriman.conflicts)
|
||||||
|
type(db).name = PropertyMock(return_value="aur")
|
||||||
|
type(mock).depends = PropertyMock(return_value=aur_package_ahriman.depends)
|
||||||
|
type(mock).desc = PropertyMock(return_value=aur_package_ahriman.description)
|
||||||
|
type(mock).licenses = PropertyMock(return_value=aur_package_ahriman.license)
|
||||||
|
type(mock).makedepends = PropertyMock(return_value=aur_package_ahriman.make_depends)
|
||||||
|
type(mock).name = PropertyMock(return_value=aur_package_ahriman.name)
|
||||||
|
type(mock).optdepends = PropertyMock(return_value=aur_package_ahriman.opt_depends)
|
||||||
|
type(mock).provides = PropertyMock(return_value=aur_package_ahriman.provides)
|
||||||
|
type(mock).version = PropertyMock(return_value=aur_package_ahriman.version)
|
||||||
|
type(mock).url = PropertyMock(return_value=aur_package_ahriman.url)
|
||||||
|
|
||||||
return mock
|
return mock
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import datetime
|
import datetime
|
||||||
import json
|
import json
|
||||||
|
import pyalpm # typing: ignore
|
||||||
|
|
||||||
from dataclasses import asdict, fields
|
from dataclasses import asdict, fields
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
@ -53,6 +54,22 @@ def test_from_json_2(aur_package_ahriman: AURPackage, mocker: MockerFixture) ->
|
|||||||
assert AURPackage.from_json(asdict(aur_package_ahriman)) == aur_package_ahriman
|
assert AURPackage.from_json(asdict(aur_package_ahriman)) == aur_package_ahriman
|
||||||
|
|
||||||
|
|
||||||
|
def test_from_pacman(pyalpm_package_ahriman: pyalpm.Package, aur_package_ahriman: AURPackage,
|
||||||
|
resource_path_root: Path) -> None:
|
||||||
|
"""
|
||||||
|
must load package from repository database
|
||||||
|
"""
|
||||||
|
model = AURPackage.from_pacman(pyalpm_package_ahriman)
|
||||||
|
# some fields are missing so we are changing them
|
||||||
|
model.id = aur_package_ahriman.id
|
||||||
|
model.package_base_id = aur_package_ahriman.package_base_id
|
||||||
|
model.first_submitted = aur_package_ahriman.first_submitted
|
||||||
|
model.url_path = aur_package_ahriman.url_path
|
||||||
|
model.maintainer = aur_package_ahriman.maintainer
|
||||||
|
|
||||||
|
assert model == aur_package_ahriman
|
||||||
|
|
||||||
|
|
||||||
def test_from_repo(aur_package_akonadi: AURPackage, resource_path_root: Path) -> None:
|
def test_from_repo(aur_package_akonadi: AURPackage, resource_path_root: Path) -> None:
|
||||||
"""
|
"""
|
||||||
must load package from repository api json
|
must load package from repository api json
|
||||||
|
@ -4,10 +4,10 @@ from pathlib import Path
|
|||||||
from pytest_mock import MockerFixture
|
from pytest_mock import MockerFixture
|
||||||
from unittest.mock import MagicMock
|
from unittest.mock import MagicMock
|
||||||
|
|
||||||
|
from ahriman.core.alpm.pacman import Pacman
|
||||||
from ahriman.core.exceptions import InvalidPackageInfo
|
from ahriman.core.exceptions import InvalidPackageInfo
|
||||||
from ahriman.models.aur_package import AURPackage
|
from ahriman.models.aur_package import AURPackage
|
||||||
from ahriman.models.package import Package
|
from ahriman.models.package import Package
|
||||||
from ahriman.models.package_source import PackageSource
|
|
||||||
from ahriman.models.repository_paths import RepositoryPaths
|
from ahriman.models.repository_paths import RepositoryPaths
|
||||||
|
|
||||||
|
|
||||||
@ -21,15 +21,6 @@ def test_depends(package_python_schedule: Package) -> None:
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def test_git_url(package_ahriman: Package) -> None:
|
|
||||||
"""
|
|
||||||
must generate valid git url
|
|
||||||
"""
|
|
||||||
assert package_ahriman.git_url.endswith(".git")
|
|
||||||
assert package_ahriman.git_url.startswith(package_ahriman.aur_url)
|
|
||||||
assert package_ahriman.base in package_ahriman.git_url
|
|
||||||
|
|
||||||
|
|
||||||
def test_groups(package_ahriman: Package) -> None:
|
def test_groups(package_ahriman: Package) -> None:
|
||||||
"""
|
"""
|
||||||
must return list of groups for each package
|
must return list of groups for each package
|
||||||
@ -80,30 +71,23 @@ def test_licenses(package_ahriman: Package) -> None:
|
|||||||
assert sorted(package_ahriman.licenses) == package_ahriman.licenses
|
assert sorted(package_ahriman.licenses) == package_ahriman.licenses
|
||||||
|
|
||||||
|
|
||||||
def test_web_url(package_ahriman: Package) -> None:
|
|
||||||
"""
|
|
||||||
must generate valid web url
|
|
||||||
"""
|
|
||||||
assert package_ahriman.web_url.startswith(package_ahriman.aur_url)
|
|
||||||
assert package_ahriman.base in package_ahriman.web_url
|
|
||||||
|
|
||||||
|
|
||||||
def test_from_archive(package_ahriman: Package, pyalpm_handle: MagicMock, mocker: MockerFixture) -> None:
|
def test_from_archive(package_ahriman: Package, pyalpm_handle: MagicMock, mocker: MockerFixture) -> None:
|
||||||
"""
|
"""
|
||||||
must construct package from alpm library
|
must construct package from alpm library
|
||||||
"""
|
"""
|
||||||
mocker.patch("ahriman.models.package_description.PackageDescription.from_package",
|
mocker.patch("ahriman.models.package_description.PackageDescription.from_package",
|
||||||
return_value=package_ahriman.packages[package_ahriman.base])
|
return_value=package_ahriman.packages[package_ahriman.base])
|
||||||
assert Package.from_archive(Path("path"), pyalpm_handle, package_ahriman.aur_url) == package_ahriman
|
assert Package.from_archive(Path("path"), pyalpm_handle, package_ahriman.remote) == package_ahriman
|
||||||
|
|
||||||
|
|
||||||
def test_from_aur(package_ahriman: Package, aur_package_ahriman: AURPackage, mocker: MockerFixture) -> None:
|
def test_from_aur(package_ahriman: Package, aur_package_ahriman: AURPackage, pacman: Pacman,
|
||||||
|
mocker: MockerFixture) -> None:
|
||||||
"""
|
"""
|
||||||
must construct package from aur
|
must construct package from aur
|
||||||
"""
|
"""
|
||||||
mocker.patch("ahriman.core.alpm.remote.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)
|
package = Package.from_aur(package_ahriman.base, pacman)
|
||||||
assert package_ahriman.base == package.base
|
assert package_ahriman.base == package.base
|
||||||
assert package_ahriman.version == package.version
|
assert package_ahriman.version == package.version
|
||||||
assert package_ahriman.packages.keys() == package.packages.keys()
|
assert package_ahriman.packages.keys() == package.packages.keys()
|
||||||
@ -114,11 +98,12 @@ def test_from_build(package_ahriman: Package, mocker: MockerFixture, resource_pa
|
|||||||
must construct package from srcinfo
|
must construct package from srcinfo
|
||||||
"""
|
"""
|
||||||
srcinfo = (resource_path_root / "models" / "package_ahriman_srcinfo").read_text()
|
srcinfo = (resource_path_root / "models" / "package_ahriman_srcinfo").read_text()
|
||||||
mocker.patch("pathlib.Path.read_text", return_value=srcinfo)
|
mocker.patch("ahriman.models.package.Package._check_output", return_value=srcinfo)
|
||||||
|
|
||||||
package = Package.from_build(Path("path"), package_ahriman.aur_url)
|
package = Package.from_build(Path("path"))
|
||||||
assert package_ahriman.packages.keys() == package.packages.keys()
|
assert package_ahriman.packages.keys() == package.packages.keys()
|
||||||
package_ahriman.packages = package.packages # we are not going to test PackageDescription here
|
package_ahriman.packages = package.packages # we are not going to test PackageDescription here
|
||||||
|
package_ahriman.remote = None
|
||||||
assert package_ahriman == package
|
assert package_ahriman == package
|
||||||
|
|
||||||
|
|
||||||
@ -126,11 +111,11 @@ def test_from_build_failed(package_ahriman: Package, mocker: MockerFixture) -> N
|
|||||||
"""
|
"""
|
||||||
must raise exception if there are errors during srcinfo load
|
must raise exception if there are errors during srcinfo load
|
||||||
"""
|
"""
|
||||||
mocker.patch("pathlib.Path.read_text", return_value="")
|
mocker.patch("ahriman.models.package.Package._check_output", return_value="")
|
||||||
mocker.patch("ahriman.models.package.parse_srcinfo", return_value=({"packages": {}}, ["an error"]))
|
mocker.patch("ahriman.models.package.parse_srcinfo", return_value=({"packages": {}}, ["an error"]))
|
||||||
|
|
||||||
with pytest.raises(InvalidPackageInfo):
|
with pytest.raises(InvalidPackageInfo):
|
||||||
Package.from_build(Path("path"), package_ahriman.aur_url)
|
Package.from_build(Path("path"))
|
||||||
|
|
||||||
|
|
||||||
def test_from_json_view_1(package_ahriman: Package) -> None:
|
def test_from_json_view_1(package_ahriman: Package) -> None:
|
||||||
@ -154,97 +139,24 @@ 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
|
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:
|
def test_from_official(package_ahriman: Package, aur_package_ahriman: AURPackage, pacman: Pacman,
|
||||||
|
mocker: MockerFixture) -> None:
|
||||||
"""
|
"""
|
||||||
must construct package from official repository
|
must construct package from official repository
|
||||||
"""
|
"""
|
||||||
mocker.patch("ahriman.core.alpm.remote.official.Official.info", return_value=aur_package_ahriman)
|
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)
|
package = Package.from_official(package_ahriman.base, pacman)
|
||||||
assert package_ahriman.base == package.base
|
assert package_ahriman.base == package.base
|
||||||
assert package_ahriman.version == package.version
|
assert package_ahriman.version == package.version
|
||||||
assert package_ahriman.packages.keys() == package.packages.keys()
|
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
|
|
||||||
"""
|
|
||||||
resolve_mock = mocker.patch("ahriman.models.package_source.PackageSource.resolve",
|
|
||||||
return_value=PackageSource.Archive)
|
|
||||||
mocker.patch("ahriman.models.package.Package.from_archive")
|
|
||||||
|
|
||||||
Package.load("path", PackageSource.Archive, pyalpm_handle, package_ahriman.aur_url)
|
|
||||||
resolve_mock.assert_called_once_with("path")
|
|
||||||
|
|
||||||
|
|
||||||
def test_load_from_archive(package_ahriman: Package, pyalpm_handle: MagicMock, mocker: MockerFixture) -> None:
|
|
||||||
"""
|
|
||||||
must load package from package archive
|
|
||||||
"""
|
|
||||||
load_mock = mocker.patch("ahriman.models.package.Package.from_archive")
|
|
||||||
Package.load("path", PackageSource.Archive, pyalpm_handle, package_ahriman.aur_url)
|
|
||||||
load_mock.assert_called_once_with(Path("path"), pyalpm_handle, package_ahriman.aur_url)
|
|
||||||
|
|
||||||
|
|
||||||
def test_load_from_aur(package_ahriman: Package, pyalpm_handle: MagicMock, mocker: MockerFixture) -> None:
|
|
||||||
"""
|
|
||||||
must load package from AUR
|
|
||||||
"""
|
|
||||||
load_mock = mocker.patch("ahriman.models.package.Package.from_aur")
|
|
||||||
Package.load("path", PackageSource.AUR, pyalpm_handle, package_ahriman.aur_url)
|
|
||||||
load_mock.assert_called_once_with("path", package_ahriman.aur_url)
|
|
||||||
|
|
||||||
|
|
||||||
def test_load_from_build(package_ahriman: Package, pyalpm_handle: MagicMock, mocker: MockerFixture) -> None:
|
|
||||||
"""
|
|
||||||
must load package from build directory
|
|
||||||
"""
|
|
||||||
load_mock = mocker.patch("ahriman.models.package.Package.from_build")
|
|
||||||
Package.load("path", PackageSource.Local, pyalpm_handle, package_ahriman.aur_url)
|
|
||||||
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
|
|
||||||
"""
|
|
||||||
mocker.patch("ahriman.models.package.Package.from_aur", side_effect=InvalidPackageInfo("exception!"))
|
|
||||||
with pytest.raises(InvalidPackageInfo):
|
|
||||||
Package.load("path", PackageSource.AUR, pyalpm_handle, package_ahriman.aur_url)
|
|
||||||
|
|
||||||
|
|
||||||
def test_load_failure_exception(package_ahriman: Package, pyalpm_handle: MagicMock, mocker: MockerFixture) -> None:
|
|
||||||
"""
|
|
||||||
must raise InvalidPackageInfo on random eexception
|
|
||||||
"""
|
|
||||||
mocker.patch("ahriman.models.package.Package.from_aur", side_effect=Exception())
|
|
||||||
with pytest.raises(InvalidPackageInfo):
|
|
||||||
Package.load("path", PackageSource.AUR, pyalpm_handle, package_ahriman.aur_url)
|
|
||||||
|
|
||||||
|
|
||||||
def test_load_invalid_source(package_ahriman: Package, pyalpm_handle: MagicMock) -> None:
|
|
||||||
"""
|
|
||||||
must raise InvalidPackageInfo on unsupported source
|
|
||||||
"""
|
|
||||||
with pytest.raises(InvalidPackageInfo):
|
|
||||||
Package.load("path", PackageSource.Remote, pyalpm_handle, package_ahriman.aur_url)
|
|
||||||
|
|
||||||
|
|
||||||
def test_dependencies_failed(mocker: MockerFixture) -> None:
|
def test_dependencies_failed(mocker: MockerFixture) -> None:
|
||||||
"""
|
"""
|
||||||
must raise exception if there are errors during srcinfo load
|
must raise exception if there are errors during srcinfo load
|
||||||
"""
|
"""
|
||||||
mocker.patch("pathlib.Path.read_text", return_value="")
|
mocker.patch("ahriman.models.package.Package._check_output", return_value="")
|
||||||
mocker.patch("ahriman.models.package.parse_srcinfo", return_value=({"packages": {}}, ["an error"]))
|
mocker.patch("ahriman.models.package.parse_srcinfo", return_value=({"packages": {}}, ["an error"]))
|
||||||
|
|
||||||
with pytest.raises(InvalidPackageInfo):
|
with pytest.raises(InvalidPackageInfo):
|
||||||
@ -256,7 +168,7 @@ def test_dependencies_with_version(mocker: MockerFixture, resource_path_root: Pa
|
|||||||
must load correct list of dependencies with version
|
must load correct list of dependencies with version
|
||||||
"""
|
"""
|
||||||
srcinfo = (resource_path_root / "models" / "package_yay_srcinfo").read_text()
|
srcinfo = (resource_path_root / "models" / "package_yay_srcinfo").read_text()
|
||||||
mocker.patch("pathlib.Path.read_text", return_value=srcinfo)
|
mocker.patch("ahriman.models.package.Package._check_output", return_value=srcinfo)
|
||||||
|
|
||||||
assert Package.dependencies(Path("path")) == {"git", "go", "pacman"}
|
assert Package.dependencies(Path("path")) == {"git", "go", "pacman"}
|
||||||
|
|
||||||
@ -266,7 +178,7 @@ def test_dependencies_with_version_and_overlap(mocker: MockerFixture, resource_p
|
|||||||
must load correct list of dependencies with version
|
must load correct list of dependencies with version
|
||||||
"""
|
"""
|
||||||
srcinfo = (resource_path_root / "models" / "package_gcc10_srcinfo").read_text()
|
srcinfo = (resource_path_root / "models" / "package_gcc10_srcinfo").read_text()
|
||||||
mocker.patch("pathlib.Path.read_text", return_value=srcinfo)
|
mocker.patch("ahriman.models.package.Package._check_output", return_value=srcinfo)
|
||||||
|
|
||||||
assert Package.dependencies(Path("path")) == {"glibc", "doxygen", "binutils", "git", "libmpc", "python", "zstd"}
|
assert Package.dependencies(Path("path")) == {"glibc", "doxygen", "binutils", "git", "libmpc", "python", "zstd"}
|
||||||
|
|
||||||
@ -328,7 +240,7 @@ def test_full_depends(package_ahriman: Package, package_python_schedule: Package
|
|||||||
assert package_ahriman.full_depends(pyalpm_handle, [package_python_schedule]) == package_ahriman.depends
|
assert package_ahriman.full_depends(pyalpm_handle, [package_python_schedule]) == package_ahriman.depends
|
||||||
|
|
||||||
package_python_schedule.packages[package_python_schedule.base].depends = [package_ahriman.base]
|
package_python_schedule.packages[package_python_schedule.base].depends = [package_ahriman.base]
|
||||||
expected = sorted(set(package_python_schedule.depends + ["python-aur"]))
|
expected = sorted(set(package_python_schedule.depends + package_ahriman.depends))
|
||||||
assert package_python_schedule.full_depends(pyalpm_handle, [package_python_schedule]) == expected
|
assert package_python_schedule.full_depends(pyalpm_handle, [package_python_schedule]) == expected
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
from dataclasses import asdict
|
|
||||||
from unittest.mock import MagicMock
|
from unittest.mock import MagicMock
|
||||||
|
|
||||||
from ahriman.models.package_description import PackageDescription
|
from ahriman.models.package_description import PackageDescription
|
||||||
@ -24,14 +23,14 @@ def test_from_json(package_description_ahriman: PackageDescription) -> None:
|
|||||||
"""
|
"""
|
||||||
must construct description from json object
|
must construct description from json object
|
||||||
"""
|
"""
|
||||||
assert PackageDescription.from_json(asdict(package_description_ahriman)) == package_description_ahriman
|
assert PackageDescription.from_json(package_description_ahriman.view()) == package_description_ahriman
|
||||||
|
|
||||||
|
|
||||||
def test_from_json_with_unknown_fields(package_description_ahriman: PackageDescription) -> None:
|
def test_from_json_with_unknown_fields(package_description_ahriman: PackageDescription) -> None:
|
||||||
"""
|
"""
|
||||||
must construct description from json object containing unknown fields
|
must construct description from json object containing unknown fields
|
||||||
"""
|
"""
|
||||||
dump = asdict(package_description_ahriman)
|
dump = package_description_ahriman.view()
|
||||||
dump.update(unknown_field="value")
|
dump.update(unknown_field="value")
|
||||||
assert PackageDescription.from_json(dump) == package_description_ahriman
|
assert PackageDescription.from_json(dump) == package_description_ahriman
|
||||||
|
|
||||||
|
82
tests/ahriman/models/test_remote_source.py
Normal file
82
tests/ahriman/models/test_remote_source.py
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
from pathlib import Path
|
||||||
|
from pytest_mock import MockerFixture
|
||||||
|
|
||||||
|
from ahriman.models.package import Package
|
||||||
|
from ahriman.models.package_source import PackageSource
|
||||||
|
from ahriman.models.remote_source import RemoteSource
|
||||||
|
|
||||||
|
|
||||||
|
def test_post_init(remote_source: RemoteSource) -> None:
|
||||||
|
"""
|
||||||
|
must convert string source to enum
|
||||||
|
"""
|
||||||
|
remote = RemoteSource(
|
||||||
|
git_url=remote_source.git_url,
|
||||||
|
web_url=remote_source.web_url,
|
||||||
|
path=remote_source.path,
|
||||||
|
branch=remote_source.branch,
|
||||||
|
source=remote_source.source.value,
|
||||||
|
)
|
||||||
|
assert remote == remote_source
|
||||||
|
|
||||||
|
|
||||||
|
def test_pkgbuild_dir(remote_source: RemoteSource) -> None:
|
||||||
|
"""
|
||||||
|
must return path as is in `path` property
|
||||||
|
"""
|
||||||
|
assert isinstance(remote_source.pkgbuild_dir, Path)
|
||||||
|
assert remote_source.pkgbuild_dir.name == ""
|
||||||
|
|
||||||
|
|
||||||
|
def test_from_json(remote_source: RemoteSource) -> None:
|
||||||
|
"""
|
||||||
|
must construct remote source from json
|
||||||
|
"""
|
||||||
|
assert RemoteSource.from_json(remote_source.view()) == remote_source
|
||||||
|
|
||||||
|
|
||||||
|
def test_from_json_empty() -> None:
|
||||||
|
"""
|
||||||
|
must return None in case of empty dictionary, which is required by the database wrapper
|
||||||
|
"""
|
||||||
|
assert RemoteSource.from_json({}) is None
|
||||||
|
|
||||||
|
|
||||||
|
def test_from_remote_aur(package_ahriman: Package, mocker: MockerFixture) -> None:
|
||||||
|
"""
|
||||||
|
must construct remote from AUR source
|
||||||
|
"""
|
||||||
|
remote_git_url_mock = mocker.patch("ahriman.core.alpm.remote.aur.AUR.remote_git_url")
|
||||||
|
remote_web_url_mock = mocker.patch("ahriman.core.alpm.remote.aur.AUR.remote_web_url")
|
||||||
|
|
||||||
|
remote = RemoteSource.from_remote(PackageSource.AUR, package_ahriman.base, "aur")
|
||||||
|
remote_git_url_mock.assert_called_once_with(package_ahriman.base, "aur")
|
||||||
|
remote_web_url_mock.assert_called_once_with(package_ahriman.base)
|
||||||
|
assert remote.pkgbuild_dir == Path(".")
|
||||||
|
assert remote.branch == "master"
|
||||||
|
assert remote.source == PackageSource.AUR
|
||||||
|
|
||||||
|
|
||||||
|
def test_from_remote_official(package_ahriman: Package, mocker: MockerFixture) -> None:
|
||||||
|
"""
|
||||||
|
must construct remote from official repository source
|
||||||
|
"""
|
||||||
|
remote_git_url_mock = mocker.patch("ahriman.core.alpm.remote.official.Official.remote_git_url")
|
||||||
|
remote_web_url_mock = mocker.patch("ahriman.core.alpm.remote.official.Official.remote_web_url")
|
||||||
|
|
||||||
|
remote = RemoteSource.from_remote(PackageSource.Repository, package_ahriman.base, "community")
|
||||||
|
remote_git_url_mock.assert_called_once_with(package_ahriman.base, "community")
|
||||||
|
remote_web_url_mock.assert_called_once_with(package_ahriman.base)
|
||||||
|
assert remote.pkgbuild_dir == Path("trunk")
|
||||||
|
assert remote.branch.endswith(package_ahriman.base)
|
||||||
|
assert remote.source == PackageSource.Repository
|
||||||
|
|
||||||
|
|
||||||
|
def test_from_remote_other() -> None:
|
||||||
|
"""
|
||||||
|
must return None in case if source is not one of AUR or Repository
|
||||||
|
"""
|
||||||
|
assert RemoteSource.from_remote(PackageSource.Archive, "package", "repository") is None
|
||||||
|
assert RemoteSource.from_remote(PackageSource.Directory, "package", "repository") is None
|
||||||
|
assert RemoteSource.from_remote(PackageSource.Local, "package", "repository") is None
|
||||||
|
assert RemoteSource.from_remote(PackageSource.Remote, "package", "repository") is None
|
@ -37,7 +37,7 @@ async def test_get_exception(client: TestClient, mocker: MockerFixture) -> None:
|
|||||||
response = await client.get("/service-api/v1/search")
|
response = await client.get("/service-api/v1/search")
|
||||||
|
|
||||||
assert response.status == 404
|
assert response.status == 404
|
||||||
search_mock.assert_called_once_with()
|
search_mock.assert_called_once_with(pacman=pytest.helpers.anyvar(int))
|
||||||
|
|
||||||
|
|
||||||
async def test_get_join(client: TestClient, mocker: MockerFixture) -> None:
|
async def test_get_join(client: TestClient, mocker: MockerFixture) -> None:
|
||||||
@ -48,4 +48,4 @@ async def test_get_join(client: TestClient, mocker: MockerFixture) -> None:
|
|||||||
response = await client.get("/service-api/v1/search", params=[("for", "ahriman"), ("for", "maybe")])
|
response = await client.get("/service-api/v1/search", params=[("for", "ahriman"), ("for", "maybe")])
|
||||||
|
|
||||||
assert response.ok
|
assert response.ok
|
||||||
search_mock.assert_called_once_with("ahriman", "maybe")
|
search_mock.assert_called_once_with("ahriman", "maybe", pacman=pytest.helpers.anyvar(int))
|
||||||
|
@ -4,7 +4,6 @@ logging = logging.ini
|
|||||||
database = ../../../ahriman-test.db
|
database = ../../../ahriman-test.db
|
||||||
|
|
||||||
[alpm]
|
[alpm]
|
||||||
aur_url = https://aur.archlinux.org
|
|
||||||
database = /var/lib/pacman
|
database = /var/lib/pacman
|
||||||
repositories = core extra community multilib
|
repositories = core extra community multilib
|
||||||
root = /
|
root = /
|
||||||
|
Loading…
Reference in New Issue
Block a user