mirror of
https://github.com/arcan1s/ahriman.git
synced 2025-04-24 15:27:17 +00:00
Local packages support improvements (#104)
* handle git author correctly * make remote source required argument
This commit is contained in:
parent
c863ee063c
commit
9259d9c727
@ -76,6 +76,14 @@ ahriman.core.database.migrations.m008\_packagers module
|
|||||||
:no-undoc-members:
|
:no-undoc-members:
|
||||||
:show-inheritance:
|
:show-inheritance:
|
||||||
|
|
||||||
|
ahriman.core.database.migrations.m009\_local\_source module
|
||||||
|
-----------------------------------------------------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.core.database.migrations.m009_local_source
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
|
||||||
Module contents
|
Module contents
|
||||||
---------------
|
---------------
|
||||||
|
|
||||||
|
@ -179,7 +179,8 @@ Available options are:
|
|||||||
Remote push trigger
|
Remote push trigger
|
||||||
^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
* ``commit_author`` - git commit author, string, optional. In case if not set, the git will generate author for you. Note, however, that in this case it will disclosure your hostname.
|
* ``commit_email`` - git commit email, string, optional, default is ``ahriman@localhost``.
|
||||||
|
* ``commit_user`` - git commit user, string, optional, default is ``ahriman``.
|
||||||
* ``push_url`` - url of the remote repository to which PKGBUILDs should be pushed after build process, string, required.
|
* ``push_url`` - url of the remote repository to which PKGBUILDs should be pushed after build process, string, required.
|
||||||
* ``push_branch`` - branch of the remote repository to which PKGBUILDs should be pushed after build process, string, optional, default is ``master``.
|
* ``push_branch`` - branch of the remote repository to which PKGBUILDs should be pushed after build process, string, optional, default is ``master``.
|
||||||
|
|
||||||
|
@ -112,7 +112,7 @@
|
|||||||
|
|
||||||
const payload = response.map(description => {
|
const payload = response.map(description => {
|
||||||
const package_base = description.package.base;
|
const package_base = description.package.base;
|
||||||
const web_url = description.package.remote?.web_url;
|
const web_url = description.package.remote.web_url;
|
||||||
return {
|
return {
|
||||||
id: package_base,
|
id: package_base,
|
||||||
base: web_url ? `<a href="${safe(web_url)}" title="${safe(package_base)}">${safe(package_base)}</a>` : safe(package_base),
|
base: web_url ? `<a href="${safe(web_url)}" title="${safe(package_base)}">${safe(package_base)}</a>` : safe(package_base),
|
||||||
|
@ -95,7 +95,7 @@ class ApplicationPackages(ApplicationProperties):
|
|||||||
if (source_dir := Path(source)).is_dir():
|
if (source_dir := Path(source)).is_dir():
|
||||||
package = Package.from_build(source_dir, self.architecture, username)
|
package = Package.from_build(source_dir, self.architecture, username)
|
||||||
cache_dir = self.repository.paths.cache_for(package.base)
|
cache_dir = self.repository.paths.cache_for(package.base)
|
||||||
shutil.copytree(source_dir, cache_dir) # copy package to store in caches
|
shutil.copytree(source_dir, cache_dir, dirs_exist_ok=True) # 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
|
||||||
elif (source_dir := self.repository.paths.cache_for(source)).is_dir():
|
elif (source_dir := self.repository.paths.cache_for(source)).is_dir():
|
||||||
package = Package.from_build(source_dir, self.architecture, username)
|
package = Package.from_build(source_dir, self.architecture, username)
|
||||||
@ -145,7 +145,7 @@ class ApplicationPackages(ApplicationProperties):
|
|||||||
username(str | None, optional): optional override of username for build process (Default value = None)
|
username(str | None, optional): optional override of username for build process (Default value = None)
|
||||||
"""
|
"""
|
||||||
for name in names:
|
for name in names:
|
||||||
resolved_source = source.resolve(name)
|
resolved_source = source.resolve(name, self.repository.paths)
|
||||||
fn = getattr(self, f"_add_{resolved_source.value}")
|
fn = getattr(self, f"_add_{resolved_source.value}")
|
||||||
fn(name, username)
|
fn(name, username)
|
||||||
|
|
||||||
|
@ -36,9 +36,11 @@ class Sources(LazyLogging):
|
|||||||
Attributes:
|
Attributes:
|
||||||
DEFAULT_BRANCH(str): (class attribute) default branch to process git repositories.
|
DEFAULT_BRANCH(str): (class attribute) default branch to process git repositories.
|
||||||
Must be used only for local stored repositories, use RemoteSource descriptor instead for real packages
|
Must be used only for local stored repositories, use RemoteSource descriptor instead for real packages
|
||||||
|
DEFAULT_COMMIT_AUTHOR(tuple[str, str]): (class attribute) default commit author to be used if none set
|
||||||
"""
|
"""
|
||||||
|
|
||||||
DEFAULT_BRANCH = "master" # default fallback branch
|
DEFAULT_BRANCH = "master" # default fallback branch
|
||||||
|
DEFAULT_COMMIT_AUTHOR = ("ahriman", "ahriman@localhost")
|
||||||
|
|
||||||
_check_output = check_output
|
_check_output = check_output
|
||||||
|
|
||||||
@ -61,13 +63,13 @@ class Sources(LazyLogging):
|
|||||||
return [PkgbuildPatch("arch", list(architectures))]
|
return [PkgbuildPatch("arch", list(architectures))]
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def fetch(sources_dir: Path, remote: RemoteSource | None) -> None:
|
def fetch(sources_dir: Path, remote: RemoteSource) -> None:
|
||||||
"""
|
"""
|
||||||
either clone repository or update it to origin/``remote.branch``
|
either clone repository or update it to origin/``remote.branch``
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
sources_dir(Path): local path to fetch
|
sources_dir(Path): local path to fetch
|
||||||
remote(RemoteSource | None): remote target (from where to fetch)
|
remote(RemoteSource): remote target (from where to fetch)
|
||||||
"""
|
"""
|
||||||
instance = Sources()
|
instance = Sources()
|
||||||
# local directory exists and there is .git directory
|
# local directory exists and there is .git directory
|
||||||
@ -77,11 +79,11 @@ class Sources(LazyLogging):
|
|||||||
instance.logger.info("skip update at %s because there are no branches configured", sources_dir)
|
instance.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 instance.DEFAULT_BRANCH
|
branch = remote.branch or instance.DEFAULT_BRANCH
|
||||||
if is_initialized_git:
|
if is_initialized_git:
|
||||||
instance.logger.info("update HEAD to remote at %s using branch %s", sources_dir, branch)
|
instance.logger.info("update HEAD to remote at %s using branch %s", sources_dir, branch)
|
||||||
Sources._check_output("git", "fetch", "origin", branch, cwd=sources_dir, logger=instance.logger)
|
Sources._check_output("git", "fetch", "origin", branch, cwd=sources_dir, logger=instance.logger)
|
||||||
elif remote is not None:
|
elif remote.git_url is not None:
|
||||||
instance.logger.info("clone remote %s to %s using branch %s", remote.git_url, sources_dir, branch)
|
instance.logger.info("clone remote %s to %s using branch %s", remote.git_url, sources_dir, branch)
|
||||||
Sources._check_output("git", "clone", "--branch", branch, "--single-branch",
|
Sources._check_output("git", "clone", "--branch", branch, "--single-branch",
|
||||||
remote.git_url, str(sources_dir), cwd=sources_dir.parent, logger=instance.logger)
|
remote.git_url, str(sources_dir), cwd=sources_dir.parent, logger=instance.logger)
|
||||||
@ -95,7 +97,7 @@ class Sources(LazyLogging):
|
|||||||
|
|
||||||
# move content if required
|
# move content if required
|
||||||
# we are using full path to source directory in order to make append possible
|
# 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()
|
pkgbuild_dir = remote.pkgbuild_dir or sources_dir.resolve()
|
||||||
instance.move((sources_dir / pkgbuild_dir).resolve(), sources_dir)
|
instance.move((sources_dir / pkgbuild_dir).resolve(), sources_dir)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
@ -122,6 +124,8 @@ class Sources(LazyLogging):
|
|||||||
sources_dir(Path): local path to sources
|
sources_dir(Path): local path to sources
|
||||||
"""
|
"""
|
||||||
instance = Sources()
|
instance = Sources()
|
||||||
|
if not (sources_dir / ".git").is_dir():
|
||||||
|
# skip initializing in case if it was already
|
||||||
Sources._check_output("git", "init", "--initial-branch", instance.DEFAULT_BRANCH,
|
Sources._check_output("git", "init", "--initial-branch", instance.DEFAULT_BRANCH,
|
||||||
cwd=sources_dir, logger=instance.logger)
|
cwd=sources_dir, logger=instance.logger)
|
||||||
|
|
||||||
@ -129,7 +133,7 @@ class Sources(LazyLogging):
|
|||||||
files = ["PKGBUILD", ".SRCINFO"] + [str(path) for path in Package.local_files(sources_dir)]
|
files = ["PKGBUILD", ".SRCINFO"] + [str(path) for path in Package.local_files(sources_dir)]
|
||||||
instance.add(sources_dir, *files)
|
instance.add(sources_dir, *files)
|
||||||
# ...and commit them
|
# ...and commit them
|
||||||
instance.commit(sources_dir, author="ahriman <ahriman@localhost>")
|
instance.commit(sources_dir)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def load(sources_dir: Path, package: Package, patches: list[PkgbuildPatch], paths: RepositoryPaths) -> None:
|
def load(sources_dir: Path, package: Package, patches: list[PkgbuildPatch], paths: RepositoryPaths) -> None:
|
||||||
@ -170,7 +174,8 @@ class Sources(LazyLogging):
|
|||||||
return f"{diff}\n" # otherwise, patch will be broken
|
return f"{diff}\n" # otherwise, patch will be broken
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def push(sources_dir: Path, remote: RemoteSource, *pattern: str, commit_author: str | None = None) -> None:
|
def push(sources_dir: Path, remote: RemoteSource, *pattern: str,
|
||||||
|
commit_author: tuple[str, str] | None = None) -> None:
|
||||||
"""
|
"""
|
||||||
commit selected changes and push files to the remote repository
|
commit selected changes and push files to the remote repository
|
||||||
|
|
||||||
@ -178,13 +183,15 @@ class Sources(LazyLogging):
|
|||||||
sources_dir(Path): local path to git repository
|
sources_dir(Path): local path to git repository
|
||||||
remote(RemoteSource): remote target, branch and url
|
remote(RemoteSource): remote target, branch and url
|
||||||
*pattern(str): glob patterns
|
*pattern(str): glob patterns
|
||||||
commit_author(str | None, optional): commit author in form of git config (i.e. ``user <user@host>``)
|
commit_author(tuple[str, str] | None, optional): commit author if any (Default value = None)
|
||||||
(Default value = None)
|
|
||||||
"""
|
"""
|
||||||
instance = Sources()
|
instance = Sources()
|
||||||
instance.add(sources_dir, *pattern)
|
instance.add(sources_dir, *pattern)
|
||||||
instance.commit(sources_dir, author=commit_author)
|
if not instance.commit(sources_dir, commit_author=commit_author):
|
||||||
Sources._check_output("git", "push", remote.git_url, remote.branch, cwd=sources_dir, logger=instance.logger)
|
return # no changes to push, just skip action
|
||||||
|
|
||||||
|
git_url, branch = remote.git_source()
|
||||||
|
Sources._check_output("git", "push", git_url, branch, cwd=sources_dir, logger=instance.logger)
|
||||||
|
|
||||||
def add(self, sources_dir: Path, *pattern: str, intent_to_add: bool = False) -> None:
|
def add(self, sources_dir: Path, *pattern: str, intent_to_add: bool = False) -> None:
|
||||||
"""
|
"""
|
||||||
@ -208,7 +215,8 @@ class Sources(LazyLogging):
|
|||||||
Sources._check_output("git", "add", *args, *[str(fn.relative_to(sources_dir)) for fn in found_files],
|
Sources._check_output("git", "add", *args, *[str(fn.relative_to(sources_dir)) for fn in found_files],
|
||||||
cwd=sources_dir, logger=self.logger)
|
cwd=sources_dir, logger=self.logger)
|
||||||
|
|
||||||
def commit(self, sources_dir: Path, message: str | None = None, author: str | None = None) -> None:
|
def commit(self, sources_dir: Path, message: str | None = None,
|
||||||
|
commit_author: tuple[str, str] | None = None) -> bool:
|
||||||
"""
|
"""
|
||||||
commit changes
|
commit changes
|
||||||
|
|
||||||
@ -216,14 +224,28 @@ class Sources(LazyLogging):
|
|||||||
sources_dir(Path): local path to git repository
|
sources_dir(Path): local path to git repository
|
||||||
message(str | None, optional): optional commit message if any. If none set, message will be generated
|
message(str | None, optional): optional commit message if any. If none set, message will be generated
|
||||||
according to the current timestamp (Default value = None)
|
according to the current timestamp (Default value = None)
|
||||||
author(str | None, optional): optional commit author if any (Default value = None)
|
commit_author(tuple[str, str] | None, optional): optional commit author if any (Default value = None)
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
bool: True in case if changes have been committed and False otherwise
|
||||||
"""
|
"""
|
||||||
|
if not self.has_changes(sources_dir):
|
||||||
|
return False # nothing to commit
|
||||||
|
|
||||||
if message is None:
|
if message is None:
|
||||||
message = f"Autogenerated commit at {utcnow()}"
|
message = f"Autogenerated commit at {utcnow()}"
|
||||||
args = ["--allow-empty", "--message", message]
|
args = ["--message", message]
|
||||||
if author is not None:
|
environment: dict[str, str] = {}
|
||||||
args.extend(["--author", author])
|
|
||||||
Sources._check_output("git", "commit", *args, cwd=sources_dir, logger=self.logger)
|
if commit_author is None:
|
||||||
|
commit_author = self.DEFAULT_COMMIT_AUTHOR
|
||||||
|
user, email = commit_author
|
||||||
|
environment["GIT_AUTHOR_NAME"] = environment["GIT_COMMITTER_NAME"] = user
|
||||||
|
environment["GIT_AUTHOR_EMAIL"] = environment["GIT_COMMITTER_EMAIL"] = email
|
||||||
|
|
||||||
|
Sources._check_output("git", "commit", *args, cwd=sources_dir, logger=self.logger, environment=environment)
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
def diff(self, sources_dir: Path) -> str:
|
def diff(self, sources_dir: Path) -> str:
|
||||||
"""
|
"""
|
||||||
@ -237,6 +259,20 @@ class Sources(LazyLogging):
|
|||||||
"""
|
"""
|
||||||
return Sources._check_output("git", "diff", cwd=sources_dir, logger=self.logger)
|
return Sources._check_output("git", "diff", cwd=sources_dir, logger=self.logger)
|
||||||
|
|
||||||
|
def has_changes(self, sources_dir: Path) -> bool:
|
||||||
|
"""
|
||||||
|
check if there are changes in current git tree
|
||||||
|
|
||||||
|
Args:
|
||||||
|
sources_dir(Path): local path to git repository
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
bool: True if there are uncommitted changes and False otherwise
|
||||||
|
"""
|
||||||
|
# there is --exit-code argument to diff, however, there might be other process errors
|
||||||
|
changes = Sources._check_output("git", "diff", "--cached", "--name-only", cwd=sources_dir, logger=self.logger)
|
||||||
|
return bool(changes)
|
||||||
|
|
||||||
def move(self, pkgbuild_dir: Path, sources_dir: Path) -> None:
|
def move(self, pkgbuild_dir: Path, sources_dir: Path) -> None:
|
||||||
"""
|
"""
|
||||||
move content from pkgbuild_dir to sources_dir
|
move content from pkgbuild_dir to sources_dir
|
||||||
|
@ -48,7 +48,7 @@ class Configuration(configparser.RawConfigParser):
|
|||||||
|
|
||||||
>>> from pathlib import Path
|
>>> from pathlib import Path
|
||||||
>>>
|
>>>
|
||||||
>>> configuration = Configuration.from_path(Path("/etc/ahriman.ini"), "x86_64", quiet=False)
|
>>> configuration = Configuration.from_path(Path("/etc/ahriman.ini"), "x86_64")
|
||||||
>>> repository_name = configuration.get("repository", "name")
|
>>> repository_name = configuration.get("repository", "name")
|
||||||
>>> makepkg_flags = configuration.getlist("build", "makepkg_flags")
|
>>> makepkg_flags = configuration.getlist("build", "makepkg_flags")
|
||||||
|
|
||||||
|
@ -70,6 +70,7 @@ def migrate_package_remotes(connection: Connection, paths: RepositoryPaths) -> N
|
|||||||
connection(Connection): database connection
|
connection(Connection): database connection
|
||||||
paths(RepositoryPaths): repository paths instance
|
paths(RepositoryPaths): repository paths instance
|
||||||
"""
|
"""
|
||||||
|
from ahriman.core.alpm.remote import AUR
|
||||||
from ahriman.core.database.operations import PackageOperations
|
from ahriman.core.database.operations import PackageOperations
|
||||||
|
|
||||||
def insert_remote(base: str, remote: RemoteSource) -> None:
|
def insert_remote(base: str, remote: RemoteSource) -> None:
|
||||||
@ -92,7 +93,11 @@ def migrate_package_remotes(connection: Connection, paths: RepositoryPaths) -> N
|
|||||||
local_cache = paths.cache_for(package_base)
|
local_cache = paths.cache_for(package_base)
|
||||||
if local_cache.exists() and not package.is_vcs:
|
if local_cache.exists() and not package.is_vcs:
|
||||||
continue # skip packages which are not VCS and with local cache
|
continue # skip packages which are not VCS and with local cache
|
||||||
remote_source = RemoteSource.from_source(PackageSource.AUR, package_base, "aur")
|
remote_source = RemoteSource(
|
||||||
if remote_source is None:
|
source=PackageSource.AUR,
|
||||||
continue # should never happen
|
git_url=AUR.remote_git_url(package_base, "aur"),
|
||||||
|
web_url=AUR.remote_web_url(package_base),
|
||||||
|
path=".",
|
||||||
|
branch="master",
|
||||||
|
)
|
||||||
insert_remote(package_base, remote_source)
|
insert_remote(package_base, remote_source)
|
||||||
|
@ -66,7 +66,7 @@ def migrate_package_depends(connection: Connection, configuration: Configuration
|
|||||||
|
|
||||||
package_list = []
|
package_list = []
|
||||||
for full_path in filter(package_like, configuration.repository_paths.repository.iterdir()):
|
for full_path in filter(package_like, configuration.repository_paths.repository.iterdir()):
|
||||||
base = Package.from_archive(full_path, pacman, remote=None)
|
base = Package.from_archive(full_path, pacman)
|
||||||
for package, description in base.packages.items():
|
for package, description in base.packages.items():
|
||||||
package_list.append({
|
package_list.append({
|
||||||
"make_depends": description.make_depends,
|
"make_depends": description.make_depends,
|
||||||
|
@ -63,7 +63,7 @@ def migrate_package_check_depends(connection: Connection, configuration: Configu
|
|||||||
|
|
||||||
package_list = []
|
package_list = []
|
||||||
for full_path in filter(package_like, configuration.repository_paths.repository.iterdir()):
|
for full_path in filter(package_like, configuration.repository_paths.repository.iterdir()):
|
||||||
base = Package.from_archive(full_path, pacman, remote=None)
|
base = Package.from_archive(full_path, pacman)
|
||||||
for package, description in base.packages.items():
|
for package, description in base.packages.items():
|
||||||
package_list.append({
|
package_list.append({
|
||||||
"check_depends": description.check_depends,
|
"check_depends": description.check_depends,
|
||||||
|
@ -69,7 +69,7 @@ def migrate_package_base_packager(connection: Connection, configuration: Configu
|
|||||||
|
|
||||||
package_list = []
|
package_list = []
|
||||||
for full_path in filter(package_like, configuration.repository_paths.repository.iterdir()):
|
for full_path in filter(package_like, configuration.repository_paths.repository.iterdir()):
|
||||||
package = Package.from_archive(full_path, pacman, remote=None)
|
package = Package.from_archive(full_path, pacman)
|
||||||
package_list.append({
|
package_list.append({
|
||||||
"package_base": package.base,
|
"package_base": package.base,
|
||||||
"packager": package.packager,
|
"packager": package.packager,
|
||||||
|
27
src/ahriman/core/database/migrations/m009_local_source.py
Normal file
27
src/ahriman/core/database/migrations/m009_local_source.py
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
#
|
||||||
|
# Copyright (c) 2021-2023 ahriman team.
|
||||||
|
#
|
||||||
|
# This file is part of ahriman
|
||||||
|
# (see https://github.com/arcan1s/ahriman).
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
#
|
||||||
|
__all__ = ["steps"]
|
||||||
|
|
||||||
|
|
||||||
|
steps = [
|
||||||
|
"""
|
||||||
|
update package_bases set source = 'local' where source is null
|
||||||
|
""",
|
||||||
|
]
|
@ -86,11 +86,11 @@ class PackageOperations(Operations):
|
|||||||
{
|
{
|
||||||
"package_base": package.base,
|
"package_base": package.base,
|
||||||
"version": package.version,
|
"version": package.version,
|
||||||
"branch": package.remote.branch if package.remote is not None else None,
|
"branch": package.remote.branch,
|
||||||
"git_url": package.remote.git_url if package.remote is not None else None,
|
"git_url": package.remote.git_url,
|
||||||
"path": package.remote.path if package.remote is not None else None,
|
"path": package.remote.path,
|
||||||
"web_url": package.remote.web_url if package.remote is not None else None,
|
"web_url": package.remote.web_url,
|
||||||
"source": package.remote.source.value if package.remote is not None else None,
|
"source": package.remote.source.value,
|
||||||
"packager": package.packager,
|
"packager": package.packager,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
@ -270,5 +270,4 @@ class PackageOperations(Operations):
|
|||||||
return {
|
return {
|
||||||
package_base: package.remote
|
package_base: package.remote
|
||||||
for package_base, package in packages.items()
|
for package_base, package in packages.items()
|
||||||
if package.remote is not None
|
|
||||||
}
|
}
|
||||||
|
@ -39,7 +39,7 @@ class RemotePush(LazyLogging):
|
|||||||
sync PKGBUILDs to remote repository after actions
|
sync PKGBUILDs to remote repository after actions
|
||||||
|
|
||||||
Attributes:
|
Attributes:
|
||||||
commit_author(str | None): optional commit author in form of git config (i.e. ``user <user@host>``)
|
commit_author(tuple[str, str] | None): optional commit author in form of git config
|
||||||
database(SQLite): database instance
|
database(SQLite): database instance
|
||||||
remote_source(RemoteSource): repository remote source (remote pull url and branch)
|
remote_source(RemoteSource): repository remote source (remote pull url and branch)
|
||||||
"""
|
"""
|
||||||
@ -54,7 +54,11 @@ class RemotePush(LazyLogging):
|
|||||||
section(str): settings section name
|
section(str): settings section name
|
||||||
"""
|
"""
|
||||||
self.database = database
|
self.database = database
|
||||||
self.commit_author = configuration.get(section, "commit_author", fallback=None)
|
|
||||||
|
commit_email = configuration.get(section, "commit_email", fallback="ahriman@localhost")
|
||||||
|
commit_user = configuration.get(section, "commit_user", fallback="ahriman")
|
||||||
|
self.commit_author = (commit_user, commit_email)
|
||||||
|
|
||||||
self.remote_source = RemoteSource(
|
self.remote_source = RemoteSource(
|
||||||
git_url=configuration.get(section, "push_url"),
|
git_url=configuration.get(section, "push_url"),
|
||||||
web_url="",
|
web_url="",
|
||||||
|
@ -49,7 +49,10 @@ class RemotePushTrigger(Trigger):
|
|||||||
"gitremote": {
|
"gitremote": {
|
||||||
"type": "dict",
|
"type": "dict",
|
||||||
"schema": {
|
"schema": {
|
||||||
"commit_author": {
|
"commit_email": {
|
||||||
|
"type": "string",
|
||||||
|
},
|
||||||
|
"commit_user": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
},
|
},
|
||||||
"push_url": {
|
"push_url": {
|
||||||
|
@ -117,8 +117,9 @@ class Repository(Executor, UpdateHandler):
|
|||||||
# 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.from_archive(full_path, self.pacman, None)
|
local = Package.from_archive(full_path, self.pacman)
|
||||||
local.remote = sources.get(local.base)
|
if (source := sources.get(local.base)) is not None:
|
||||||
|
local.remote = source
|
||||||
|
|
||||||
current = result.setdefault(local.base, local)
|
current = result.setdefault(local.base, local)
|
||||||
if current.version != local.version:
|
if current.version != local.version:
|
||||||
|
@ -24,6 +24,7 @@ from ahriman.core.exceptions import UnknownPackageError
|
|||||||
from ahriman.core.repository.cleaner import Cleaner
|
from ahriman.core.repository.cleaner import Cleaner
|
||||||
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
|
||||||
|
|
||||||
|
|
||||||
class UpdateHandler(Cleaner):
|
class UpdateHandler(Cleaner):
|
||||||
@ -55,12 +56,10 @@ class UpdateHandler(Cleaner):
|
|||||||
list[Package]: list of packages which are out-of-dated
|
list[Package]: list of packages which are out-of-dated
|
||||||
"""
|
"""
|
||||||
def load_remote(package: Package) -> Package:
|
def load_remote(package: Package) -> Package:
|
||||||
source = package.remote.source if package.remote is not None else None
|
|
||||||
|
|
||||||
# try to load package from base and if none found try to load by separated packages
|
# try to load package from base and if none found try to load by separated packages
|
||||||
for probe in [package.base] + sorted(package.packages.keys()):
|
for probe in [package.base] + sorted(package.packages.keys()):
|
||||||
try:
|
try:
|
||||||
if source == PackageSource.Repository:
|
if package.remote.source == PackageSource.Repository:
|
||||||
return Package.from_official(probe, self.pacman, None)
|
return Package.from_official(probe, self.pacman, None)
|
||||||
return Package.from_aur(probe, self.pacman, None)
|
return Package.from_aur(probe, self.pacman, None)
|
||||||
except UnknownPackageError:
|
except UnknownPackageError:
|
||||||
@ -71,6 +70,8 @@ class UpdateHandler(Cleaner):
|
|||||||
|
|
||||||
for local in self.packages():
|
for local in self.packages():
|
||||||
with self.in_package_context(local.base):
|
with self.in_package_context(local.base):
|
||||||
|
if not local.remote.is_remote:
|
||||||
|
continue # avoid checking local packages
|
||||||
if local.base in self.ignore_list:
|
if local.base in self.ignore_list:
|
||||||
continue
|
continue
|
||||||
if filter_packages and local.base not in filter_packages:
|
if filter_packages and local.base not in filter_packages:
|
||||||
@ -107,7 +108,15 @@ class UpdateHandler(Cleaner):
|
|||||||
for cache_dir in self.paths.cache.iterdir():
|
for cache_dir in self.paths.cache.iterdir():
|
||||||
with self.in_package_context(cache_dir.name):
|
with self.in_package_context(cache_dir.name):
|
||||||
try:
|
try:
|
||||||
Sources.fetch(cache_dir, remote=None)
|
source = RemoteSource(
|
||||||
|
source=PackageSource.Local,
|
||||||
|
git_url=cache_dir.absolute().as_uri(),
|
||||||
|
web_url="",
|
||||||
|
path=".",
|
||||||
|
branch="master",
|
||||||
|
)
|
||||||
|
|
||||||
|
Sources.fetch(cache_dir, source)
|
||||||
remote = Package.from_build(cache_dir, self.architecture, None)
|
remote = Package.from_build(cache_dir, self.architecture, None)
|
||||||
|
|
||||||
local = packages.get(remote.base)
|
local = packages.get(remote.base)
|
||||||
|
@ -27,7 +27,6 @@ from multiprocessing import Process, Queue
|
|||||||
from threading import Lock, Thread
|
from threading import Lock, Thread
|
||||||
|
|
||||||
from ahriman.core.log import LazyLogging
|
from ahriman.core.log import LazyLogging
|
||||||
from ahriman.models.package_source import PackageSource
|
|
||||||
|
|
||||||
|
|
||||||
class Spawn(Thread, LazyLogging):
|
class Spawn(Thread, LazyLogging):
|
||||||
@ -133,8 +132,7 @@ class Spawn(Thread, LazyLogging):
|
|||||||
username(str | None): optional override of username for build process
|
username(str | None): optional override of username for build process
|
||||||
now(bool): build packages now
|
now(bool): build packages now
|
||||||
"""
|
"""
|
||||||
# avoid abusing by building non-aur packages
|
kwargs = {"username": username}
|
||||||
kwargs = {"source": PackageSource.AUR.value, "username": username}
|
|
||||||
if now:
|
if now:
|
||||||
kwargs["now"] = ""
|
kwargs["now"] = ""
|
||||||
self._spawn_process("package-add", *packages, **kwargs)
|
self._spawn_process("package-add", *packages, **kwargs)
|
||||||
|
@ -304,7 +304,7 @@ def parse_version(version: str) -> tuple[str | None, str, str]:
|
|||||||
|
|
||||||
def partition(source: list[T], predicate: Callable[[T], bool]) -> tuple[list[T], list[T]]:
|
def partition(source: list[T], predicate: Callable[[T], bool]) -> tuple[list[T], list[T]]:
|
||||||
"""
|
"""
|
||||||
partition list into two based on predicate, based on # https://docs.python.org/dev/library/itertools.html#itertools-recipes
|
partition list into two based on predicate, based on https://docs.python.org/dev/library/itertools.html#itertools-recipes
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
source(list[T]): source list to be partitioned
|
source(list[T]): source list to be partitioned
|
||||||
|
@ -66,13 +66,12 @@ class AURPackage:
|
|||||||
>>> package = AURPackage.from_repo(metadata) # load package from official repository RPC
|
>>> package = AURPackage.from_repo(metadata) # load package from official repository RPC
|
||||||
>>> # properties of the class are built based on ones from AUR RPC, thus additional method is required
|
>>> # properties of the class are built based on ones from AUR RPC, thus additional method is required
|
||||||
>>>
|
>>>
|
||||||
>>>
|
|
||||||
>>> from ahriman.core.alpm.pacman import Pacman
|
>>> from ahriman.core.alpm.pacman import Pacman
|
||||||
>>> from ahriman.core.configuration import Configuration
|
>>> from ahriman.core.configuration import Configuration
|
||||||
>>>
|
>>>
|
||||||
>>> configuration = Configuration()
|
>>> configuration = Configuration()
|
||||||
>>> pacman = Pacman("x86_64", configuration)
|
>>> pacman = Pacman("x86_64", configuration)
|
||||||
>>> metadata = pacman.get("pacman")
|
>>> metadata = pacman.package_get("pacman")
|
||||||
>>> package = AURPackage.from_pacman(next(metadata)) # load package from pyalpm wrapper
|
>>> package = AURPackage.from_pacman(next(metadata)) # load package from pyalpm wrapper
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
@ -51,7 +51,7 @@ class Package(LazyLogging):
|
|||||||
packager(str | None): package packager if available
|
packager(str | None): package packager if available
|
||||||
packages(dict[str, PackageDescription): map of package names to their properties.
|
packages(dict[str, PackageDescription): map of package names to their properties.
|
||||||
Filled only on load from archive
|
Filled only on load from archive
|
||||||
remote(RemoteSource | None): package remote source if applicable
|
remote(RemoteSource): package remote source if applicable
|
||||||
version(str): package full version
|
version(str): package full version
|
||||||
|
|
||||||
Examples:
|
Examples:
|
||||||
@ -61,7 +61,7 @@ class Package(LazyLogging):
|
|||||||
|
|
||||||
it will contain every data available in the json body. Otherwise, if generate package from local archive::
|
it will contain every data available in the json body. Otherwise, if generate package from local archive::
|
||||||
|
|
||||||
>>> package = Package.from_archive(local_path, pacman, remote=None)
|
>>> package = Package.from_archive(local_path, pacman)
|
||||||
|
|
||||||
it will probably miss file descriptions (in case if there are multiple packages which belong to the base).
|
it will probably miss file descriptions (in case if there are multiple packages which belong to the base).
|
||||||
|
|
||||||
@ -76,7 +76,7 @@ class Package(LazyLogging):
|
|||||||
|
|
||||||
base: str
|
base: str
|
||||||
version: str
|
version: str
|
||||||
remote: RemoteSource | None
|
remote: RemoteSource
|
||||||
packages: dict[str, PackageDescription]
|
packages: dict[str, PackageDescription]
|
||||||
packager: str | None = None
|
packager: str | None = None
|
||||||
|
|
||||||
@ -192,22 +192,26 @@ class Package(LazyLogging):
|
|||||||
return sorted(packages)
|
return sorted(packages)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_archive(cls, path: Path, pacman: Pacman, remote: RemoteSource | None) -> Self:
|
def from_archive(cls, path: Path, pacman: Pacman) -> Self:
|
||||||
"""
|
"""
|
||||||
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
|
||||||
remote(RemoteSource): package remote source if applicable
|
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Self: package properties
|
Self: package properties
|
||||||
"""
|
"""
|
||||||
package = pacman.handle.load_pkg(str(path))
|
package = pacman.handle.load_pkg(str(path))
|
||||||
description = PackageDescription.from_package(package, path)
|
description = PackageDescription.from_package(package, path)
|
||||||
return cls(base=package.base, version=package.version, remote=remote, packages={package.name: description},
|
return cls(
|
||||||
packager=package.packager)
|
base=package.base,
|
||||||
|
version=package.version,
|
||||||
|
remote=RemoteSource(source=PackageSource.Archive),
|
||||||
|
packages={package.name: description},
|
||||||
|
packager=package.packager,
|
||||||
|
)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_aur(cls, name: str, pacman: Pacman, packager: str | None = None) -> Self:
|
def from_aur(cls, name: str, pacman: Pacman, packager: str | None = None) -> Self:
|
||||||
@ -223,7 +227,15 @@ class Package(LazyLogging):
|
|||||||
Self: package properties
|
Self: package properties
|
||||||
"""
|
"""
|
||||||
package = AUR.info(name, pacman=pacman)
|
package = AUR.info(name, pacman=pacman)
|
||||||
remote = RemoteSource.from_source(PackageSource.AUR, package.package_base, package.repository)
|
|
||||||
|
remote = RemoteSource(
|
||||||
|
source=PackageSource.AUR,
|
||||||
|
git_url=AUR.remote_git_url(package.package_base, package.repository),
|
||||||
|
web_url=AUR.remote_web_url(package.package_base),
|
||||||
|
path=".",
|
||||||
|
branch="master",
|
||||||
|
)
|
||||||
|
|
||||||
return cls(
|
return cls(
|
||||||
base=package.package_base,
|
base=package.package_base,
|
||||||
version=package.version,
|
version=package.version,
|
||||||
@ -265,14 +277,20 @@ class Package(LazyLogging):
|
|||||||
version = full_version(srcinfo.get("epoch"), srcinfo["pkgver"], srcinfo["pkgrel"])
|
version = full_version(srcinfo.get("epoch"), srcinfo["pkgver"], srcinfo["pkgrel"])
|
||||||
|
|
||||||
remote = RemoteSource(
|
remote = RemoteSource(
|
||||||
|
source=PackageSource.Local,
|
||||||
git_url=path.absolute().as_uri(),
|
git_url=path.absolute().as_uri(),
|
||||||
web_url="",
|
web_url=None,
|
||||||
path=".",
|
path=".",
|
||||||
branch="master",
|
branch="master",
|
||||||
source=PackageSource.Local,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
return cls(base=srcinfo["pkgbase"], version=version, remote=remote, packages=packages, packager=packager)
|
return cls(
|
||||||
|
base=srcinfo["pkgbase"],
|
||||||
|
version=version,
|
||||||
|
remote=remote,
|
||||||
|
packages=packages,
|
||||||
|
packager=packager,
|
||||||
|
)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_json(cls, dump: dict[str, Any]) -> Self:
|
def from_json(cls, dump: dict[str, Any]) -> Self:
|
||||||
@ -291,8 +309,13 @@ class Package(LazyLogging):
|
|||||||
for key, value in packages_json.items()
|
for key, value in packages_json.items()
|
||||||
}
|
}
|
||||||
remote = dump.get("remote") or {}
|
remote = dump.get("remote") or {}
|
||||||
return cls(base=dump["base"], version=dump["version"], remote=RemoteSource.from_json(remote), packages=packages,
|
return cls(
|
||||||
packager=dump.get("packager"))
|
base=dump["base"],
|
||||||
|
version=dump["version"],
|
||||||
|
remote=RemoteSource.from_json(remote),
|
||||||
|
packages=packages,
|
||||||
|
packager=dump.get("packager"),
|
||||||
|
)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_official(cls, name: str, pacman: Pacman, packager: str | None = None, *, use_syncdb: bool = True) -> Self:
|
def from_official(cls, name: str, pacman: Pacman, packager: str | None = None, *, use_syncdb: bool = True) -> Self:
|
||||||
@ -309,7 +332,15 @@ class Package(LazyLogging):
|
|||||||
Self: package properties
|
Self: package properties
|
||||||
"""
|
"""
|
||||||
package = OfficialSyncdb.info(name, pacman=pacman) if use_syncdb else Official.info(name, pacman=pacman)
|
package = OfficialSyncdb.info(name, pacman=pacman) if use_syncdb else Official.info(name, pacman=pacman)
|
||||||
remote = RemoteSource.from_source(PackageSource.Repository, package.package_base, package.repository)
|
|
||||||
|
remote = RemoteSource(
|
||||||
|
source=PackageSource.Repository,
|
||||||
|
git_url=Official.remote_git_url(package.package_base, package.repository),
|
||||||
|
web_url=Official.remote_web_url(package.package_base),
|
||||||
|
path=".",
|
||||||
|
branch="main",
|
||||||
|
)
|
||||||
|
|
||||||
return cls(
|
return cls(
|
||||||
base=package.package_base,
|
base=package.package_base,
|
||||||
version=package.version,
|
version=package.version,
|
||||||
|
@ -53,14 +53,13 @@ class PackageDescription:
|
|||||||
|
|
||||||
>>> description = PackageDescription.from_json(dump)
|
>>> description = PackageDescription.from_json(dump)
|
||||||
>>>
|
>>>
|
||||||
>>>
|
|
||||||
>>> from pathlib import Path
|
>>> from pathlib import Path
|
||||||
>>> from ahriman.core.alpm.pacman import Pacman
|
>>> from ahriman.core.alpm.pacman import Pacman
|
||||||
>>> from ahriman.core.configuration import Configuration
|
>>> from ahriman.core.configuration import Configuration
|
||||||
>>>
|
>>>
|
||||||
>>> configuration = Configuration()
|
>>> configuration = Configuration()
|
||||||
>>> pacman = Pacman("x86_64", configuration)
|
>>> pacman = Pacman("x86_64", configuration)
|
||||||
>>> pyalpm_description = next(package for package in pacman.get("pacman"))
|
>>> pyalpm_description = next(package for package in pacman.package_get("pacman"))
|
||||||
>>> description = PackageDescription.from_package(
|
>>> description = PackageDescription.from_package(
|
||||||
>>> pyalpm_description, Path("/var/cache/pacman/pkg/pacman-6.0.1-4-x86_64.pkg.tar.zst"))
|
>>> pyalpm_description, Path("/var/cache/pacman/pkg/pacman-6.0.1-4-x86_64.pkg.tar.zst"))
|
||||||
"""
|
"""
|
||||||
|
@ -24,6 +24,7 @@ from pathlib import Path
|
|||||||
from urllib.parse import urlparse
|
from urllib.parse import urlparse
|
||||||
|
|
||||||
from ahriman.core.util import package_like
|
from ahriman.core.util import package_like
|
||||||
|
from ahriman.models.repository_paths import RepositoryPaths
|
||||||
|
|
||||||
|
|
||||||
class PackageSource(str, Enum):
|
class PackageSource(str, Enum):
|
||||||
@ -42,7 +43,7 @@ class PackageSource(str, Enum):
|
|||||||
Examples:
|
Examples:
|
||||||
In case if source is unknown the ``resolve()`` and the source descriptor is available method must be used::
|
In case if source is unknown the ``resolve()`` and the source descriptor is available method must be used::
|
||||||
|
|
||||||
>>> real_source = PackageSource.Auto.resolve("ahriman")
|
>>> real_source = PackageSource.Auto.resolve("ahriman", configuration.repository_paths)
|
||||||
|
|
||||||
the code above will ensure that the presudo-source ``PackageSource.Auto`` will not be processed later.
|
the code above will ensure that the presudo-source ``PackageSource.Auto`` will not be processed later.
|
||||||
"""
|
"""
|
||||||
@ -55,12 +56,13 @@ class PackageSource(str, Enum):
|
|||||||
Remote = "remote"
|
Remote = "remote"
|
||||||
Repository = "repository"
|
Repository = "repository"
|
||||||
|
|
||||||
def resolve(self, source: str) -> PackageSource:
|
def resolve(self, source: str, paths: RepositoryPaths) -> PackageSource:
|
||||||
"""
|
"""
|
||||||
resolve auto into the correct type
|
resolve auto into the correct type
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
source(str): source of the package
|
source(str): source of the package
|
||||||
|
paths(RepositoryPaths): repository paths instance
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
PackageSource: non-auto type of the package source
|
PackageSource: non-auto type of the package source
|
||||||
@ -74,7 +76,7 @@ class PackageSource(str, Enum):
|
|||||||
if maybe_url.scheme and maybe_url.scheme not in ("data", "file") and package_like(maybe_path):
|
if maybe_url.scheme and maybe_url.scheme not in ("data", "file") and package_like(maybe_path):
|
||||||
return PackageSource.Remote
|
return PackageSource.Remote
|
||||||
try:
|
try:
|
||||||
if (maybe_path / "PKGBUILD").is_file():
|
if (maybe_path / "PKGBUILD").is_file() or paths.cache_for(source).is_dir():
|
||||||
return PackageSource.Local
|
return PackageSource.Local
|
||||||
if maybe_path.is_dir():
|
if maybe_path.is_dir():
|
||||||
return PackageSource.Directory
|
return PackageSource.Directory
|
||||||
|
@ -21,6 +21,7 @@ from dataclasses import dataclass, fields
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Any, Self
|
from typing import Any, Self
|
||||||
|
|
||||||
|
from ahriman.core.exceptions import InitializeError
|
||||||
from ahriman.core.util import dataclass_view, filter_json
|
from ahriman.core.util import dataclass_view, filter_json
|
||||||
from ahriman.models.package_source import PackageSource
|
from ahriman.models.package_source import PackageSource
|
||||||
|
|
||||||
@ -31,18 +32,18 @@ class RemoteSource:
|
|||||||
remote package source properties
|
remote package source properties
|
||||||
|
|
||||||
Attributes:
|
Attributes:
|
||||||
branch(str): branch of the git repository
|
branch(str | None): branch of the git repository
|
||||||
git_url(str): url of the git repository
|
git_url(str | None): url of the git repository
|
||||||
path(str): path to directory with PKGBUILD inside the git repository
|
path(str | None): path to directory with PKGBUILD inside the git repository
|
||||||
source(PackageSource): package source pointer used by some parsers
|
source(PackageSource): package source pointer used by some parsers
|
||||||
web_url(str): url of the package in the web interface
|
web_url(str | None): url of the package in the web interface
|
||||||
"""
|
"""
|
||||||
|
|
||||||
git_url: str
|
|
||||||
web_url: str
|
|
||||||
path: str
|
|
||||||
branch: str
|
|
||||||
source: PackageSource
|
source: PackageSource
|
||||||
|
git_url: str | None = None
|
||||||
|
web_url: str | None = None
|
||||||
|
path: str | None = None
|
||||||
|
branch: str | None = None
|
||||||
|
|
||||||
def __post_init__(self) -> None:
|
def __post_init__(self) -> None:
|
||||||
"""
|
"""
|
||||||
@ -51,17 +52,27 @@ class RemoteSource:
|
|||||||
object.__setattr__(self, "source", PackageSource(self.source))
|
object.__setattr__(self, "source", PackageSource(self.source))
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def pkgbuild_dir(self) -> Path:
|
def is_remote(self) -> bool:
|
||||||
|
"""
|
||||||
|
check if source is remote
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
bool: True in case if package is well-known remote source (e.g. AUR) and False otherwise
|
||||||
|
"""
|
||||||
|
return self.source in (PackageSource.AUR, PackageSource.Repository)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def pkgbuild_dir(self) -> Path | None:
|
||||||
"""
|
"""
|
||||||
get path to directory with package sources (PKGBUILD etc)
|
get path to directory with package sources (PKGBUILD etc)
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Path: path to directory with package sources based on settings
|
Path | None: path to directory with package sources based on settings if available
|
||||||
"""
|
"""
|
||||||
return Path(self.path)
|
return Path(self.path) if self.path is not None else None
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_json(cls, dump: dict[str, Any]) -> Self | None:
|
def from_json(cls, dump: dict[str, Any]) -> Self:
|
||||||
"""
|
"""
|
||||||
construct remote source from the json dump (or database row)
|
construct remote source from the json dump (or database row)
|
||||||
|
|
||||||
@ -69,47 +80,25 @@ class RemoteSource:
|
|||||||
dump(dict[str, Any]): json dump body
|
dump(dict[str, Any]): json dump body
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Self | None: remote source
|
Self: remote source
|
||||||
"""
|
"""
|
||||||
# filter to only known fields
|
# filter to only known fields
|
||||||
known_fields = [pair.name for pair in fields(cls)]
|
known_fields = [pair.name for pair in fields(cls)]
|
||||||
dump = filter_json(dump, known_fields)
|
return cls(**filter_json(dump, known_fields))
|
||||||
if dump:
|
|
||||||
return cls(**dump)
|
|
||||||
return None
|
|
||||||
|
|
||||||
@classmethod
|
def git_source(self) -> tuple[str, str]:
|
||||||
def from_source(cls, source: PackageSource, package_base: str, repository: str) -> Self | None:
|
|
||||||
"""
|
"""
|
||||||
generate remote source from the package base
|
get git source if available
|
||||||
|
|
||||||
Args:
|
|
||||||
source(PackageSource): source of the package
|
|
||||||
package_base(str): package base
|
|
||||||
repository(str): repository name
|
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Self | None: generated remote source if any, None otherwise
|
tuple[str, str]: git url and branch
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
InitializeError: in case if git url and/or branch are not set
|
||||||
"""
|
"""
|
||||||
if source == PackageSource.AUR:
|
if self.git_url is None or self.branch is None:
|
||||||
from ahriman.core.alpm.remote import AUR
|
raise InitializeError("Remote source is empty")
|
||||||
return cls(
|
return self.git_url, self.branch
|
||||||
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 import Official
|
|
||||||
return cls(
|
|
||||||
git_url=Official.remote_git_url(package_base, repository),
|
|
||||||
web_url=Official.remote_web_url(package_base),
|
|
||||||
path=".",
|
|
||||||
branch="main",
|
|
||||||
source=source,
|
|
||||||
)
|
|
||||||
return None
|
|
||||||
|
|
||||||
def view(self) -> dict[str, Any]:
|
def view(self) -> dict[str, Any]:
|
||||||
"""
|
"""
|
||||||
|
@ -41,7 +41,7 @@ class User:
|
|||||||
Simply create user from database data and perform required validation::
|
Simply create user from database data and perform required validation::
|
||||||
|
|
||||||
>>> password = User.generate_password(24)
|
>>> password = User.generate_password(24)
|
||||||
>>> user = User(username="ahriman", password=password, access=UserAccess.Full, packager_id=None, key=None)
|
>>> user = User(username="ahriman", password=password, access=UserAccess.Full)
|
||||||
|
|
||||||
Since the password supplied may be plain text, the ``hash_password`` method can be used to hash the password::
|
Since the password supplied may be plain text, the ``hash_password`` method can be used to hash the password::
|
||||||
|
|
||||||
@ -63,8 +63,8 @@ class User:
|
|||||||
username: str
|
username: str
|
||||||
password: str
|
password: str
|
||||||
access: UserAccess
|
access: UserAccess
|
||||||
packager_id: str | None
|
packager_id: str | None = None
|
||||||
key: str | None
|
key: str | None = None
|
||||||
|
|
||||||
_HASHER = sha512_crypt
|
_HASHER = sha512_crypt
|
||||||
|
|
||||||
|
@ -27,22 +27,22 @@ class RemoteSchema(Schema):
|
|||||||
request and response package remote schema
|
request and response package remote schema
|
||||||
"""
|
"""
|
||||||
|
|
||||||
branch = fields.String(required=True, metadata={
|
branch = fields.String(metadata={
|
||||||
"description": "Repository branch",
|
"description": "Repository branch",
|
||||||
"example": "master",
|
"example": "master",
|
||||||
})
|
})
|
||||||
git_url = fields.String(required=True, metadata={
|
git_url = fields.String(metadata={
|
||||||
"description": "Package git url",
|
"description": "Package git url",
|
||||||
"example": "https://aur.archlinux.org/ahriman.git",
|
"example": "https://aur.archlinux.org/ahriman.git",
|
||||||
})
|
})
|
||||||
path = fields.String(required=True, metadata={
|
path = fields.String(metadata={
|
||||||
"description": "Path to package sources in git repository",
|
"description": "Path to package sources in git repository",
|
||||||
"example": ".",
|
"example": ".",
|
||||||
})
|
})
|
||||||
source = fields.Enum(PackageSource, by_value=True, required=True, metadata={
|
source = fields.Enum(PackageSource, by_value=True, required=True, metadata={
|
||||||
"description": "Pacakge source",
|
"description": "Pacakge source",
|
||||||
})
|
})
|
||||||
web_url = fields.String(required=True, metadata={
|
web_url = fields.String(metadata={
|
||||||
"description": "Package repository page",
|
"description": "Package repository page",
|
||||||
"example": "https://aur.archlinux.org/packages/ahriman",
|
"example": "https://aur.archlinux.org/packages/ahriman",
|
||||||
})
|
})
|
||||||
|
@ -86,7 +86,9 @@ def test_add_local(application_packages: ApplicationPackages, package_ahriman: P
|
|||||||
application_packages._add_local(package_ahriman.base, "packager")
|
application_packages._add_local(package_ahriman.base, "packager")
|
||||||
is_dir_mock.assert_called_once_with()
|
is_dir_mock.assert_called_once_with()
|
||||||
copytree_mock.assert_called_once_with(
|
copytree_mock.assert_called_once_with(
|
||||||
Path(package_ahriman.base), application_packages.repository.paths.cache_for(package_ahriman.base))
|
Path(package_ahriman.base),
|
||||||
|
application_packages.repository.paths.cache_for(package_ahriman.base),
|
||||||
|
dirs_exist_ok=True)
|
||||||
init_mock.assert_called_once_with(application_packages.repository.paths.cache_for(package_ahriman.base))
|
init_mock.assert_called_once_with(application_packages.repository.paths.cache_for(package_ahriman.base))
|
||||||
build_queue_mock.assert_called_once_with(package_ahriman)
|
build_queue_mock.assert_called_once_with(package_ahriman)
|
||||||
|
|
||||||
|
@ -7,6 +7,7 @@ from typing import Any, TypeVar
|
|||||||
from unittest.mock import MagicMock
|
from unittest.mock import MagicMock
|
||||||
|
|
||||||
from ahriman.core.alpm.pacman import Pacman
|
from ahriman.core.alpm.pacman import Pacman
|
||||||
|
from ahriman.core.alpm.remote import AUR
|
||||||
from ahriman.core.auth import Auth
|
from ahriman.core.auth import Auth
|
||||||
from ahriman.core.configuration import Configuration
|
from ahriman.core.configuration import Configuration
|
||||||
from ahriman.core.database import SQLite
|
from ahriman.core.database import SQLite
|
||||||
@ -314,7 +315,13 @@ def package_python_schedule(
|
|||||||
return Package(
|
return Package(
|
||||||
base="python-schedule",
|
base="python-schedule",
|
||||||
version="1.0.0-2",
|
version="1.0.0-2",
|
||||||
remote=RemoteSource.from_source(PackageSource.AUR, "python-schedule", "aur"),
|
remote=RemoteSource(
|
||||||
|
source=PackageSource.AUR,
|
||||||
|
git_url=AUR.remote_git_url("python-schedule", "aur"),
|
||||||
|
web_url=AUR.remote_web_url("python-schedule"),
|
||||||
|
path=".",
|
||||||
|
branch="master",
|
||||||
|
),
|
||||||
packages=packages)
|
packages=packages)
|
||||||
|
|
||||||
|
|
||||||
@ -451,7 +458,13 @@ def remote_source() -> RemoteSource:
|
|||||||
Returns:
|
Returns:
|
||||||
RemoteSource: remote source test instance
|
RemoteSource: remote source test instance
|
||||||
"""
|
"""
|
||||||
return RemoteSource.from_source(PackageSource.AUR, "ahriman", "aur")
|
return RemoteSource(
|
||||||
|
source=PackageSource.AUR,
|
||||||
|
git_url=AUR.remote_git_url("ahriman", "aur"),
|
||||||
|
web_url=AUR.remote_web_url("ahriman"),
|
||||||
|
path=".",
|
||||||
|
branch="master",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
|
@ -8,6 +8,7 @@ from unittest.mock import MagicMock
|
|||||||
|
|
||||||
from ahriman.core.alpm.pacman import Pacman
|
from ahriman.core.alpm.pacman import Pacman
|
||||||
from ahriman.core.configuration import Configuration
|
from ahriman.core.configuration import Configuration
|
||||||
|
from ahriman.models.pacman_synchronization import PacmanSynchronization
|
||||||
from ahriman.models.repository_paths import RepositoryPaths
|
from ahriman.models.repository_paths import RepositoryPaths
|
||||||
|
|
||||||
|
|
||||||
@ -23,7 +24,7 @@ def test_init_with_local_cache(configuration: Configuration, mocker: MockerFixtu
|
|||||||
with TemporaryDirectory(ignore_cleanup_errors=True) as pacman_root:
|
with TemporaryDirectory(ignore_cleanup_errors=True) as pacman_root:
|
||||||
mocker.patch.object(RepositoryPaths, "pacman", Path(pacman_root))
|
mocker.patch.object(RepositoryPaths, "pacman", Path(pacman_root))
|
||||||
# during the creation pyalpm.Handle will create also version file which we would like to remove later
|
# during the creation pyalpm.Handle will create also version file which we would like to remove later
|
||||||
pacman = Pacman("x86_64", configuration, refresh_database=1)
|
pacman = Pacman("x86_64", configuration, refresh_database=PacmanSynchronization.Enabled)
|
||||||
assert pacman.handle
|
assert pacman.handle
|
||||||
sync_mock.assert_called_once_with(pytest.helpers.anyvar(int), force=False)
|
sync_mock.assert_called_once_with(pytest.helpers.anyvar(int), force=False)
|
||||||
|
|
||||||
@ -40,7 +41,7 @@ def test_init_with_local_cache_forced(configuration: Configuration, mocker: Mock
|
|||||||
with TemporaryDirectory(ignore_cleanup_errors=True) as pacman_root:
|
with TemporaryDirectory(ignore_cleanup_errors=True) as pacman_root:
|
||||||
mocker.patch.object(RepositoryPaths, "pacman", Path(pacman_root))
|
mocker.patch.object(RepositoryPaths, "pacman", Path(pacman_root))
|
||||||
# during the creation pyalpm.Handle will create also version file which we would like to remove later
|
# during the creation pyalpm.Handle will create also version file which we would like to remove later
|
||||||
pacman = Pacman("x86_64", configuration, refresh_database=2)
|
pacman = Pacman("x86_64", configuration, refresh_database=PacmanSynchronization.Force)
|
||||||
assert pacman.handle
|
assert pacman.handle
|
||||||
sync_mock.assert_called_once_with(pytest.helpers.anyvar(int), force=True)
|
sync_mock.assert_called_once_with(pytest.helpers.anyvar(int), force=True)
|
||||||
|
|
||||||
@ -54,7 +55,7 @@ def test_database_copy(pacman: Pacman, repository_paths: RepositoryPaths, mocker
|
|||||||
dst_path = Path("/var/lib/pacman/sync/core.db")
|
dst_path = Path("/var/lib/pacman/sync/core.db")
|
||||||
mocker.patch("pathlib.Path.is_dir", return_value=True)
|
mocker.patch("pathlib.Path.is_dir", return_value=True)
|
||||||
# root database exists, local database does not
|
# root database exists, local database does not
|
||||||
mocker.patch("pathlib.Path.is_file", autospec=True, side_effect=lambda p: True if p.is_relative_to(path) else False)
|
mocker.patch("pathlib.Path.is_file", autospec=True, side_effect=lambda p: p.is_relative_to(path))
|
||||||
copy_mock = mocker.patch("shutil.copy")
|
copy_mock = mocker.patch("shutil.copy")
|
||||||
chown_mock = mocker.patch("ahriman.models.repository_paths.RepositoryPaths.chown")
|
chown_mock = mocker.patch("ahriman.models.repository_paths.RepositoryPaths.chown")
|
||||||
|
|
||||||
@ -71,7 +72,7 @@ def test_database_copy_skip(pacman: Pacman, repository_paths: RepositoryPaths, m
|
|||||||
path = Path("randomname")
|
path = Path("randomname")
|
||||||
mocker.patch("pathlib.Path.is_dir", return_value=True)
|
mocker.patch("pathlib.Path.is_dir", return_value=True)
|
||||||
# root database exists, local database does not
|
# root database exists, local database does not
|
||||||
mocker.patch("pathlib.Path.is_file", autospec=True, side_effect=lambda p: True if p.is_relative_to(path) else False)
|
mocker.patch("pathlib.Path.is_file", autospec=True, side_effect=lambda p: p.is_relative_to(path))
|
||||||
copy_mock = mocker.patch("shutil.copy")
|
copy_mock = mocker.patch("shutil.copy")
|
||||||
|
|
||||||
pacman.database_copy(pacman.handle, database, path, repository_paths, use_ahriman_cache=False)
|
pacman.database_copy(pacman.handle, database, path, repository_paths, use_ahriman_cache=False)
|
||||||
@ -86,7 +87,7 @@ def test_database_copy_no_directory(pacman: Pacman, repository_paths: Repository
|
|||||||
path = Path("randomname")
|
path = Path("randomname")
|
||||||
mocker.patch("pathlib.Path.is_dir", return_value=False)
|
mocker.patch("pathlib.Path.is_dir", return_value=False)
|
||||||
# root database exists, local database does not
|
# root database exists, local database does not
|
||||||
mocker.patch("pathlib.Path.is_file", autospec=True, side_effect=lambda p: True if p.is_relative_to(path) else False)
|
mocker.patch("pathlib.Path.is_file", autospec=True, side_effect=lambda p: p.is_relative_to(path))
|
||||||
copy_mock = mocker.patch("shutil.copy")
|
copy_mock = mocker.patch("shutil.copy")
|
||||||
|
|
||||||
pacman.database_copy(pacman.handle, database, path, repository_paths, use_ahriman_cache=True)
|
pacman.database_copy(pacman.handle, database, path, repository_paths, use_ahriman_cache=True)
|
||||||
|
@ -6,6 +6,7 @@ from unittest.mock import call as MockCall
|
|||||||
|
|
||||||
from ahriman.core.build_tools.sources import Sources
|
from ahriman.core.build_tools.sources import Sources
|
||||||
from ahriman.models.package import Package
|
from ahriman.models.package import Package
|
||||||
|
from ahriman.models.package_source import PackageSource
|
||||||
from ahriman.models.pkgbuild_patch import PkgbuildPatch
|
from ahriman.models.pkgbuild_patch import PkgbuildPatch
|
||||||
from ahriman.models.remote_source import RemoteSource
|
from ahriman.models.remote_source import RemoteSource
|
||||||
from ahriman.models.repository_paths import RepositoryPaths
|
from ahriman.models.repository_paths import RepositoryPaths
|
||||||
@ -92,7 +93,7 @@ def test_fetch_new_without_remote(mocker: MockerFixture) -> None:
|
|||||||
move_mock = mocker.patch("ahriman.core.build_tools.sources.Sources.move")
|
move_mock = mocker.patch("ahriman.core.build_tools.sources.Sources.move")
|
||||||
|
|
||||||
local = Path("local")
|
local = Path("local")
|
||||||
Sources.fetch(local, None)
|
Sources.fetch(local, RemoteSource(source=PackageSource.Archive))
|
||||||
check_output_mock.assert_has_calls([
|
check_output_mock.assert_has_calls([
|
||||||
MockCall("git", "checkout", "--force", Sources.DEFAULT_BRANCH, cwd=local, logger=pytest.helpers.anyvar(int)),
|
MockCall("git", "checkout", "--force", Sources.DEFAULT_BRANCH, cwd=local, logger=pytest.helpers.anyvar(int)),
|
||||||
MockCall("git", "reset", "--hard", f"origin/{Sources.DEFAULT_BRANCH}",
|
MockCall("git", "reset", "--hard", f"origin/{Sources.DEFAULT_BRANCH}",
|
||||||
@ -136,6 +137,7 @@ def test_init(mocker: MockerFixture) -> None:
|
|||||||
must create empty repository at the specified path
|
must create empty repository at the specified path
|
||||||
"""
|
"""
|
||||||
mocker.patch("ahriman.models.package.Package.local_files", return_value=[Path("local")])
|
mocker.patch("ahriman.models.package.Package.local_files", return_value=[Path("local")])
|
||||||
|
mocker.patch("pathlib.Path.is_dir", return_value=False)
|
||||||
add_mock = mocker.patch("ahriman.core.build_tools.sources.Sources.add")
|
add_mock = mocker.patch("ahriman.core.build_tools.sources.Sources.add")
|
||||||
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")
|
||||||
commit_mock = mocker.patch("ahriman.core.build_tools.sources.Sources.commit")
|
commit_mock = mocker.patch("ahriman.core.build_tools.sources.Sources.commit")
|
||||||
@ -145,7 +147,21 @@ def test_init(mocker: MockerFixture) -> None:
|
|||||||
check_output_mock.assert_called_once_with("git", "init", "--initial-branch", Sources.DEFAULT_BRANCH,
|
check_output_mock.assert_called_once_with("git", "init", "--initial-branch", Sources.DEFAULT_BRANCH,
|
||||||
cwd=local, logger=pytest.helpers.anyvar(int))
|
cwd=local, logger=pytest.helpers.anyvar(int))
|
||||||
add_mock.assert_called_once_with(local, "PKGBUILD", ".SRCINFO", "local")
|
add_mock.assert_called_once_with(local, "PKGBUILD", ".SRCINFO", "local")
|
||||||
commit_mock.assert_called_once_with(local, author="ahriman <ahriman@localhost>")
|
commit_mock.assert_called_once_with(local)
|
||||||
|
|
||||||
|
|
||||||
|
def test_init_skip(mocker: MockerFixture) -> None:
|
||||||
|
"""
|
||||||
|
must skip git init if it was already
|
||||||
|
"""
|
||||||
|
mocker.patch("ahriman.models.package.Package.local_files", return_value=[Path("local")])
|
||||||
|
mocker.patch("pathlib.Path.is_dir", return_value=True)
|
||||||
|
mocker.patch("ahriman.core.build_tools.sources.Sources.add")
|
||||||
|
mocker.patch("ahriman.core.build_tools.sources.Sources.commit")
|
||||||
|
check_output_mock = mocker.patch("ahriman.core.build_tools.sources.Sources._check_output")
|
||||||
|
|
||||||
|
Sources.init(Path("local"))
|
||||||
|
check_output_mock.assert_not_called()
|
||||||
|
|
||||||
|
|
||||||
def test_load(package_ahriman: Package, repository_paths: RepositoryPaths, mocker: MockerFixture) -> None:
|
def test_load(package_ahriman: Package, repository_paths: RepositoryPaths, mocker: MockerFixture) -> None:
|
||||||
@ -216,19 +232,31 @@ def test_push(package_ahriman: Package, mocker: MockerFixture) -> None:
|
|||||||
must correctly push files to remote repository
|
must correctly push files to remote repository
|
||||||
"""
|
"""
|
||||||
add_mock = mocker.patch("ahriman.core.build_tools.sources.Sources.add")
|
add_mock = mocker.patch("ahriman.core.build_tools.sources.Sources.add")
|
||||||
commit_mock = mocker.patch("ahriman.core.build_tools.sources.Sources.commit")
|
commit_mock = mocker.patch("ahriman.core.build_tools.sources.Sources.commit", 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")
|
||||||
|
|
||||||
author = "commit author <user@host>"
|
commit_author = ("commit author", "user@host")
|
||||||
local = Path("local")
|
local = Path("local")
|
||||||
Sources.push(Path("local"), package_ahriman.remote, "glob", commit_author=author)
|
Sources.push(local, package_ahriman.remote, "glob", commit_author=commit_author)
|
||||||
add_mock.assert_called_once_with(local, "glob")
|
add_mock.assert_called_once_with(local, "glob")
|
||||||
commit_mock.assert_called_once_with(local, author=author)
|
commit_mock.assert_called_once_with(local, commit_author=commit_author)
|
||||||
check_output_mock.assert_called_once_with(
|
check_output_mock.assert_called_once_with(
|
||||||
"git", "push", package_ahriman.remote.git_url, package_ahriman.remote.branch,
|
"git", "push", package_ahriman.remote.git_url, package_ahriman.remote.branch,
|
||||||
cwd=local, logger=pytest.helpers.anyvar(int))
|
cwd=local, logger=pytest.helpers.anyvar(int))
|
||||||
|
|
||||||
|
|
||||||
|
def test_push_skipped(package_ahriman: Package, mocker: MockerFixture) -> None:
|
||||||
|
"""
|
||||||
|
must skip push if no changes were committed
|
||||||
|
"""
|
||||||
|
mocker.patch("ahriman.core.build_tools.sources.Sources.add")
|
||||||
|
mocker.patch("ahriman.core.build_tools.sources.Sources.commit", return_value=False)
|
||||||
|
check_output_mock = mocker.patch("ahriman.core.build_tools.sources.Sources._check_output")
|
||||||
|
|
||||||
|
Sources.push(Path("local"), package_ahriman.remote)
|
||||||
|
check_output_mock.assert_not_called()
|
||||||
|
|
||||||
|
|
||||||
def test_add(sources: Sources, mocker: MockerFixture) -> None:
|
def test_add(sources: Sources, mocker: MockerFixture) -> None:
|
||||||
"""
|
"""
|
||||||
must add files to git
|
must add files to git
|
||||||
@ -274,29 +302,54 @@ def test_commit(sources: Sources, mocker: MockerFixture) -> None:
|
|||||||
"""
|
"""
|
||||||
must commit changes
|
must commit changes
|
||||||
"""
|
"""
|
||||||
|
mocker.patch("ahriman.core.build_tools.sources.Sources.has_changes", 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")
|
||||||
|
|
||||||
local = Path("local")
|
local = Path("local")
|
||||||
message = "Commit message"
|
message = "Commit message"
|
||||||
sources.commit(local, message=message)
|
user, email = sources.DEFAULT_COMMIT_AUTHOR
|
||||||
|
assert sources.commit(local, message=message)
|
||||||
check_output_mock.assert_called_once_with(
|
check_output_mock.assert_called_once_with(
|
||||||
"git", "commit", "--allow-empty", "--message", message, cwd=local, logger=pytest.helpers.anyvar(int)
|
"git", "commit", "--message", message,
|
||||||
|
cwd=local, logger=pytest.helpers.anyvar(int), environment={
|
||||||
|
"GIT_AUTHOR_NAME": user,
|
||||||
|
"GIT_AUTHOR_EMAIL": email,
|
||||||
|
"GIT_COMMITTER_NAME": user,
|
||||||
|
"GIT_COMMITTER_EMAIL": email,
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_commit_no_changes(sources: Sources, mocker: MockerFixture) -> None:
|
||||||
|
"""
|
||||||
|
must skip commit if there are no changes
|
||||||
|
"""
|
||||||
|
mocker.patch("ahriman.core.build_tools.sources.Sources.has_changes", return_value=False)
|
||||||
|
check_output_mock = mocker.patch("ahriman.core.build_tools.sources.Sources._check_output")
|
||||||
|
|
||||||
|
assert not sources.commit(Path("local"))
|
||||||
|
check_output_mock.assert_not_called()
|
||||||
|
|
||||||
|
|
||||||
def test_commit_author(sources: Sources, mocker: MockerFixture) -> None:
|
def test_commit_author(sources: Sources, mocker: MockerFixture) -> None:
|
||||||
"""
|
"""
|
||||||
must commit changes with commit author
|
must commit changes with commit author
|
||||||
"""
|
"""
|
||||||
|
mocker.patch("ahriman.core.build_tools.sources.Sources.has_changes", 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")
|
||||||
|
|
||||||
local = Path("local")
|
local = Path("local")
|
||||||
message = "Commit message"
|
message = "Commit message"
|
||||||
author = "commit author <user@host>"
|
user, email = author = ("commit author", "user@host")
|
||||||
sources.commit(Path("local"), message=message, author=author)
|
assert sources.commit(Path("local"), message=message, commit_author=author)
|
||||||
check_output_mock.assert_called_once_with(
|
check_output_mock.assert_called_once_with(
|
||||||
"git", "commit", "--allow-empty", "--message", message, "--author", author,
|
"git", "commit", "--message", message,
|
||||||
cwd=local, logger=pytest.helpers.anyvar(int)
|
cwd=local, logger=pytest.helpers.anyvar(int), environment={
|
||||||
|
"GIT_AUTHOR_NAME": user,
|
||||||
|
"GIT_AUTHOR_EMAIL": email,
|
||||||
|
"GIT_COMMITTER_NAME": user,
|
||||||
|
"GIT_COMMITTER_EMAIL": email,
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -304,13 +357,20 @@ def test_commit_autogenerated_message(sources: Sources, mocker: MockerFixture) -
|
|||||||
"""
|
"""
|
||||||
must commit changes with autogenerated commit message
|
must commit changes with autogenerated commit message
|
||||||
"""
|
"""
|
||||||
|
mocker.patch("ahriman.core.build_tools.sources.Sources.has_changes", 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")
|
||||||
|
|
||||||
local = Path("local")
|
local = Path("local")
|
||||||
sources.commit(Path("local"))
|
assert sources.commit(Path("local"))
|
||||||
|
user, email = sources.DEFAULT_COMMIT_AUTHOR
|
||||||
check_output_mock.assert_called_once_with(
|
check_output_mock.assert_called_once_with(
|
||||||
"git", "commit", "--allow-empty", "--message", pytest.helpers.anyvar(str, strict=True),
|
"git", "commit", "--message", pytest.helpers.anyvar(str, strict=True),
|
||||||
cwd=local, logger=pytest.helpers.anyvar(int)
|
cwd=local, logger=pytest.helpers.anyvar(int), environment={
|
||||||
|
"GIT_AUTHOR_NAME": user,
|
||||||
|
"GIT_AUTHOR_EMAIL": email,
|
||||||
|
"GIT_COMMITTER_NAME": user,
|
||||||
|
"GIT_COMMITTER_EMAIL": email,
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -325,6 +385,23 @@ def test_diff(sources: Sources, mocker: MockerFixture) -> None:
|
|||||||
check_output_mock.assert_called_once_with("git", "diff", cwd=local, logger=pytest.helpers.anyvar(int))
|
check_output_mock.assert_called_once_with("git", "diff", cwd=local, logger=pytest.helpers.anyvar(int))
|
||||||
|
|
||||||
|
|
||||||
|
def test_has_changes(sources: Sources, mocker: MockerFixture) -> None:
|
||||||
|
"""
|
||||||
|
must correctly identify if there are changes
|
||||||
|
"""
|
||||||
|
local = Path("local")
|
||||||
|
|
||||||
|
check_output_mock = mocker.patch("ahriman.core.build_tools.sources.Sources._check_output", return_value="M a.txt")
|
||||||
|
assert sources.has_changes(local)
|
||||||
|
check_output_mock.assert_called_once_with("git", "diff", "--cached", "--name-only",
|
||||||
|
cwd=local, logger=pytest.helpers.anyvar(int))
|
||||||
|
|
||||||
|
check_output_mock = mocker.patch("ahriman.core.build_tools.sources.Sources._check_output", return_value="")
|
||||||
|
assert not sources.has_changes(local)
|
||||||
|
check_output_mock.assert_called_once_with("git", "diff", "--cached", "--name-only",
|
||||||
|
cwd=local, logger=pytest.helpers.anyvar(int))
|
||||||
|
|
||||||
|
|
||||||
def test_move(sources: Sources, mocker: MockerFixture) -> None:
|
def test_move(sources: Sources, mocker: MockerFixture) -> None:
|
||||||
"""
|
"""
|
||||||
must move content between directories
|
must move content between directories
|
||||||
|
@ -66,18 +66,3 @@ def test_migrate_package_remotes_vcs(package_ahriman: Package, connection: Conne
|
|||||||
|
|
||||||
migrate_package_remotes(connection, repository_paths)
|
migrate_package_remotes(connection, repository_paths)
|
||||||
connection.execute.assert_called_once_with(pytest.helpers.anyvar(str, strict=True), pytest.helpers.anyvar(int))
|
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.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_source", return_value=None)
|
|
||||||
|
|
||||||
migrate_package_remotes(connection, repository_paths)
|
|
||||||
connection.execute.assert_not_called()
|
|
||||||
|
@ -35,7 +35,7 @@ def test_migrate_package_depends(connection: Connection, configuration: Configur
|
|||||||
|
|
||||||
migrate_package_depends(connection, configuration)
|
migrate_package_depends(connection, configuration)
|
||||||
package_mock.assert_called_once_with(
|
package_mock.assert_called_once_with(
|
||||||
package_ahriman.packages[package_ahriman.base].filepath, pytest.helpers.anyvar(int), remote=None)
|
package_ahriman.packages[package_ahriman.base].filepath, pytest.helpers.anyvar(int))
|
||||||
connection.executemany.assert_called_once_with(pytest.helpers.anyvar(str, strict=True), [{
|
connection.executemany.assert_called_once_with(pytest.helpers.anyvar(str, strict=True), [{
|
||||||
"make_depends": package_ahriman.packages[package_ahriman.base].make_depends,
|
"make_depends": package_ahriman.packages[package_ahriman.base].make_depends,
|
||||||
"opt_depends": package_ahriman.packages[package_ahriman.base].opt_depends,
|
"opt_depends": package_ahriman.packages[package_ahriman.base].opt_depends,
|
||||||
|
@ -35,7 +35,7 @@ def test_migrate_package_depends(connection: Connection, configuration: Configur
|
|||||||
|
|
||||||
migrate_package_check_depends(connection, configuration)
|
migrate_package_check_depends(connection, configuration)
|
||||||
package_mock.assert_called_once_with(
|
package_mock.assert_called_once_with(
|
||||||
package_ahriman.packages[package_ahriman.base].filepath, pytest.helpers.anyvar(int), remote=None)
|
package_ahriman.packages[package_ahriman.base].filepath, pytest.helpers.anyvar(int))
|
||||||
connection.executemany.assert_called_once_with(pytest.helpers.anyvar(str, strict=True), [{
|
connection.executemany.assert_called_once_with(pytest.helpers.anyvar(str, strict=True), [{
|
||||||
"check_depends": package_ahriman.packages[package_ahriman.base].check_depends,
|
"check_depends": package_ahriman.packages[package_ahriman.base].check_depends,
|
||||||
"package": package_ahriman.base,
|
"package": package_ahriman.base,
|
||||||
|
@ -35,7 +35,7 @@ def test_migrate_package_base_packager(connection: Connection, configuration: Co
|
|||||||
|
|
||||||
migrate_package_base_packager(connection, configuration)
|
migrate_package_base_packager(connection, configuration)
|
||||||
package_mock.assert_called_once_with(
|
package_mock.assert_called_once_with(
|
||||||
package_ahriman.packages[package_ahriman.base].filepath, pytest.helpers.anyvar(int), remote=None)
|
package_ahriman.packages[package_ahriman.base].filepath, pytest.helpers.anyvar(int))
|
||||||
connection.executemany.assert_called_once_with(pytest.helpers.anyvar(str, strict=True), [{
|
connection.executemany.assert_called_once_with(pytest.helpers.anyvar(str, strict=True), [{
|
||||||
"package_base": package_ahriman.base,
|
"package_base": package_ahriman.base,
|
||||||
"packager": package_ahriman.packager,
|
"packager": package_ahriman.packager,
|
||||||
|
@ -0,0 +1,8 @@
|
|||||||
|
from ahriman.core.database.migrations.m009_local_source import steps
|
||||||
|
|
||||||
|
|
||||||
|
def test_migration_packagers() -> None:
|
||||||
|
"""
|
||||||
|
migration must not be empty
|
||||||
|
"""
|
||||||
|
assert steps
|
@ -193,7 +193,7 @@ def test_remote_update_update(database: SQLite, package_ahriman: Package) -> Non
|
|||||||
must perform package remote update for existing package
|
must perform package remote update for existing package
|
||||||
"""
|
"""
|
||||||
database.remote_update(package_ahriman)
|
database.remote_update(package_ahriman)
|
||||||
remote_source = RemoteSource.from_source(PackageSource.Repository, package_ahriman.base, "community")
|
remote_source = RemoteSource(source=PackageSource.Repository)
|
||||||
package_ahriman.remote = remote_source
|
package_ahriman.remote = remote_source
|
||||||
|
|
||||||
database.remote_update(package_ahriman)
|
database.remote_update(package_ahriman)
|
||||||
|
@ -11,6 +11,8 @@ from ahriman.core.repository import Repository
|
|||||||
from ahriman.core.sign.gpg import GPG
|
from ahriman.core.sign.gpg import GPG
|
||||||
from ahriman.models.context_key import ContextKey
|
from ahriman.models.context_key import ContextKey
|
||||||
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_load(configuration: Configuration, database: SQLite, mocker: MockerFixture) -> None:
|
def test_load(configuration: Configuration, database: SQLite, mocker: MockerFixture) -> None:
|
||||||
@ -51,6 +53,9 @@ def test_load_archives(package_ahriman: Package, package_python_schedule: Packag
|
|||||||
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.from_archive", side_effect=single_packages)
|
mocker.patch("ahriman.models.package.Package.from_archive", side_effect=single_packages)
|
||||||
|
mocker.patch("ahriman.core.database.SQLite.remotes_get", return_value={
|
||||||
|
package_ahriman.base: package_ahriman.base
|
||||||
|
})
|
||||||
|
|
||||||
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
|
||||||
|
@ -42,7 +42,7 @@ def test_updates_aur_official(update_handler: UpdateHandler, package_ahriman: Pa
|
|||||||
"""
|
"""
|
||||||
must provide updates based on repository data
|
must provide updates based on repository data
|
||||||
"""
|
"""
|
||||||
package_ahriman.remote = RemoteSource.from_source(PackageSource.Repository, package_ahriman.base, "community")
|
package_ahriman.remote = RemoteSource(source=PackageSource.Repository)
|
||||||
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.from_official", return_value=package_ahriman)
|
mocker.patch("ahriman.models.package.Package.from_official", return_value=package_ahriman)
|
||||||
@ -65,6 +65,19 @@ def test_updates_aur_failed(update_handler: UpdateHandler, package_ahriman: Pack
|
|||||||
status_client_mock.assert_called_once_with(package_ahriman.base)
|
status_client_mock.assert_called_once_with(package_ahriman.base)
|
||||||
|
|
||||||
|
|
||||||
|
def test_updates_aur_local(update_handler: UpdateHandler, package_ahriman: Package,
|
||||||
|
mocker: MockerFixture) -> None:
|
||||||
|
"""
|
||||||
|
must skip packages with local sources
|
||||||
|
"""
|
||||||
|
package_ahriman.remote = RemoteSource(source=PackageSource.Local)
|
||||||
|
mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.packages", return_value=[package_ahriman])
|
||||||
|
package_load_mock = mocker.patch("ahriman.models.package.Package.from_aur")
|
||||||
|
|
||||||
|
assert not update_handler.updates_aur([], vcs=True)
|
||||||
|
package_load_mock.assert_not_called()
|
||||||
|
|
||||||
|
|
||||||
def test_updates_aur_filter(update_handler: UpdateHandler, package_ahriman: Package, package_python_schedule: Package,
|
def test_updates_aur_filter(update_handler: UpdateHandler, package_ahriman: Package, package_python_schedule: Package,
|
||||||
mocker: MockerFixture) -> None:
|
mocker: MockerFixture) -> None:
|
||||||
"""
|
"""
|
||||||
@ -150,7 +163,7 @@ def test_updates_local(update_handler: UpdateHandler, package_ahriman: Package,
|
|||||||
package_is_outdated_mock = mocker.patch("ahriman.models.package.Package.is_outdated", return_value=True)
|
package_is_outdated_mock = mocker.patch("ahriman.models.package.Package.is_outdated", return_value=True)
|
||||||
|
|
||||||
assert update_handler.updates_local(vcs=True) == [package_ahriman]
|
assert update_handler.updates_local(vcs=True) == [package_ahriman]
|
||||||
fetch_mock.assert_called_once_with(Path(package_ahriman.base), remote=None)
|
fetch_mock.assert_called_once_with(Path(package_ahriman.base), pytest.helpers.anyvar(int))
|
||||||
package_load_mock.assert_called_once_with(Path(package_ahriman.base), "x86_64", None)
|
package_load_mock.assert_called_once_with(Path(package_ahriman.base), "x86_64", None)
|
||||||
status_client_mock.assert_called_once_with(package_ahriman.base)
|
status_client_mock.assert_called_once_with(package_ahriman.base)
|
||||||
package_is_outdated_mock.assert_called_once_with(
|
package_is_outdated_mock.assert_called_once_with(
|
||||||
|
@ -75,7 +75,7 @@ def test_packages_add(spawner: Spawn, mocker: MockerFixture) -> None:
|
|||||||
"""
|
"""
|
||||||
spawn_mock = mocker.patch("ahriman.core.spawn.Spawn._spawn_process")
|
spawn_mock = mocker.patch("ahriman.core.spawn.Spawn._spawn_process")
|
||||||
spawner.packages_add(["ahriman", "linux"], None, now=False)
|
spawner.packages_add(["ahriman", "linux"], None, now=False)
|
||||||
spawn_mock.assert_called_once_with("package-add", "ahriman", "linux", source="aur", username=None)
|
spawn_mock.assert_called_once_with("package-add", "ahriman", "linux", username=None)
|
||||||
|
|
||||||
|
|
||||||
def test_packages_add_with_build(spawner: Spawn, mocker: MockerFixture) -> None:
|
def test_packages_add_with_build(spawner: Spawn, mocker: MockerFixture) -> None:
|
||||||
@ -84,7 +84,7 @@ def test_packages_add_with_build(spawner: Spawn, mocker: MockerFixture) -> None:
|
|||||||
"""
|
"""
|
||||||
spawn_mock = mocker.patch("ahriman.core.spawn.Spawn._spawn_process")
|
spawn_mock = mocker.patch("ahriman.core.spawn.Spawn._spawn_process")
|
||||||
spawner.packages_add(["ahriman", "linux"], None, now=True)
|
spawner.packages_add(["ahriman", "linux"], None, now=True)
|
||||||
spawn_mock.assert_called_once_with("package-add", "ahriman", "linux", source="aur", username=None, now="")
|
spawn_mock.assert_called_once_with("package-add", "ahriman", "linux", username=None, now="")
|
||||||
|
|
||||||
|
|
||||||
def test_packages_add_with_username(spawner: Spawn, mocker: MockerFixture) -> None:
|
def test_packages_add_with_username(spawner: Spawn, mocker: MockerFixture) -> None:
|
||||||
@ -93,7 +93,7 @@ def test_packages_add_with_username(spawner: Spawn, mocker: MockerFixture) -> No
|
|||||||
"""
|
"""
|
||||||
spawn_mock = mocker.patch("ahriman.core.spawn.Spawn._spawn_process")
|
spawn_mock = mocker.patch("ahriman.core.spawn.Spawn._spawn_process")
|
||||||
spawner.packages_add(["ahriman", "linux"], "username", now=False)
|
spawner.packages_add(["ahriman", "linux"], "username", now=False)
|
||||||
spawn_mock.assert_called_once_with("package-add", "ahriman", "linux", source="aur", username="username")
|
spawn_mock.assert_called_once_with("package-add", "ahriman", "linux", username="username")
|
||||||
|
|
||||||
|
|
||||||
def test_packages_rebuild(spawner: Spawn, mocker: MockerFixture) -> None:
|
def test_packages_rebuild(spawner: Spawn, mocker: MockerFixture) -> None:
|
||||||
|
@ -4,6 +4,7 @@ import pytest
|
|||||||
from unittest.mock import MagicMock, PropertyMock
|
from unittest.mock import MagicMock, PropertyMock
|
||||||
|
|
||||||
from ahriman import __version__
|
from ahriman import __version__
|
||||||
|
from ahriman.core.alpm.remote import AUR
|
||||||
from ahriman.models.aur_package import AURPackage
|
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
|
||||||
@ -70,7 +71,13 @@ 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",
|
||||||
remote=RemoteSource.from_source(PackageSource.AUR, "tpacpi-bat-git", "aur"),
|
remote=RemoteSource(
|
||||||
|
source=PackageSource.AUR,
|
||||||
|
git_url=AUR.remote_git_url("tpacpi-bat-git", "aur"),
|
||||||
|
web_url=AUR.remote_web_url("tpacpi-bat-git"),
|
||||||
|
path=".",
|
||||||
|
branch="master",
|
||||||
|
),
|
||||||
packages={"tpacpi-bat-git": PackageDescription()})
|
packages={"tpacpi-bat-git": PackageDescription()})
|
||||||
|
|
||||||
|
|
||||||
|
@ -158,7 +158,10 @@ def test_from_archive(package_ahriman: Package, pyalpm_handle: MagicMock, mocker
|
|||||||
"""
|
"""
|
||||||
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.remote) == package_ahriman
|
generated = Package.from_archive(Path("path"), pyalpm_handle)
|
||||||
|
generated.remote = package_ahriman.remote
|
||||||
|
|
||||||
|
assert generated == package_ahriman
|
||||||
|
|
||||||
|
|
||||||
def test_from_aur(package_ahriman: Package, aur_package_ahriman: AURPackage, pacman: Pacman,
|
def test_from_aur(package_ahriman: Package, aur_package_ahriman: AURPackage, pacman: Pacman,
|
||||||
|
@ -4,6 +4,7 @@ from pathlib import Path
|
|||||||
|
|
||||||
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.repository_paths import RepositoryPaths
|
||||||
|
|
||||||
|
|
||||||
def _is_file_mock(is_any_file: bool, is_pkgbuild: bool) -> Callable[[Path], bool]:
|
def _is_file_mock(is_any_file: bool, is_pkgbuild: bool) -> Callable[[Path], bool]:
|
||||||
@ -21,71 +22,86 @@ def _is_file_mock(is_any_file: bool, is_pkgbuild: bool) -> Callable[[Path], bool
|
|||||||
return side_effect
|
return side_effect
|
||||||
|
|
||||||
|
|
||||||
def test_resolve_non_auto() -> None:
|
def test_resolve_non_auto(repository_paths: RepositoryPaths) -> None:
|
||||||
"""
|
"""
|
||||||
must resolve non auto type to itself
|
must resolve non auto type to itself
|
||||||
"""
|
"""
|
||||||
for source in filter(lambda src: src != PackageSource.Auto, PackageSource):
|
for source in filter(lambda src: src != PackageSource.Auto, PackageSource):
|
||||||
assert source.resolve("") == source
|
assert source.resolve("", repository_paths) == source
|
||||||
|
|
||||||
|
|
||||||
def test_resolve_archive(package_description_ahriman: PackageDescription, mocker: MockerFixture) -> None:
|
def test_resolve_archive(package_description_ahriman: PackageDescription, repository_paths: RepositoryPaths,
|
||||||
|
mocker: MockerFixture) -> None:
|
||||||
"""
|
"""
|
||||||
must resolve auto type into the archive
|
must resolve auto type into the archive
|
||||||
"""
|
"""
|
||||||
mocker.patch("pathlib.Path.is_dir", return_value=False)
|
mocker.patch("pathlib.Path.is_dir", return_value=False)
|
||||||
mocker.patch("pathlib.Path.is_file", autospec=True, side_effect=_is_file_mock(True, False))
|
mocker.patch("pathlib.Path.is_file", autospec=True, side_effect=_is_file_mock(True, False))
|
||||||
assert PackageSource.Auto.resolve(package_description_ahriman.filename) == PackageSource.Archive
|
assert PackageSource.Auto.resolve(package_description_ahriman.filename, repository_paths) == PackageSource.Archive
|
||||||
|
|
||||||
|
|
||||||
def test_resolve_aur(mocker: MockerFixture) -> None:
|
def test_resolve_aur(repository_paths: RepositoryPaths, mocker: MockerFixture) -> None:
|
||||||
"""
|
"""
|
||||||
must resolve auto type into the AUR package
|
must resolve auto type into the AUR package
|
||||||
"""
|
"""
|
||||||
mocker.patch("pathlib.Path.is_dir", return_value=False)
|
mocker.patch("pathlib.Path.is_dir", return_value=False)
|
||||||
mocker.patch("pathlib.Path.is_file", return_value=False)
|
mocker.patch("pathlib.Path.is_file", return_value=False)
|
||||||
assert PackageSource.Auto.resolve("package") == PackageSource.AUR
|
assert PackageSource.Auto.resolve("package", repository_paths) == PackageSource.AUR
|
||||||
|
|
||||||
|
|
||||||
def test_resolve_aur_not_package_like(mocker: MockerFixture) -> None:
|
def test_resolve_aur_not_package_like(repository_paths: RepositoryPaths, mocker: MockerFixture) -> None:
|
||||||
"""
|
"""
|
||||||
must resolve auto type into the AUR package if it is file, but does not look like a package archive
|
must resolve auto type into the AUR package if it is file, but does not look like a package archive
|
||||||
"""
|
"""
|
||||||
mocker.patch("pathlib.Path.is_dir", return_value=False)
|
mocker.patch("pathlib.Path.is_dir", return_value=False)
|
||||||
mocker.patch("pathlib.Path.is_file", autospec=True, side_effect=_is_file_mock(True, False))
|
mocker.patch("pathlib.Path.is_file", autospec=True, side_effect=_is_file_mock(True, False))
|
||||||
assert PackageSource.Auto.resolve("package") == PackageSource.AUR
|
assert PackageSource.Auto.resolve("package", repository_paths) == PackageSource.AUR
|
||||||
|
|
||||||
|
|
||||||
def test_resolve_aur_no_access(mocker: MockerFixture) -> None:
|
def test_resolve_aur_no_access(repository_paths: RepositoryPaths, mocker: MockerFixture) -> None:
|
||||||
"""
|
"""
|
||||||
must resolve auto type into the AUR package in case if we cannot read in suggested path
|
must resolve auto type into the AUR package in case if we cannot read in suggested path
|
||||||
"""
|
"""
|
||||||
mocker.patch("pathlib.Path.is_dir", side_effect=PermissionError())
|
mocker.patch("pathlib.Path.is_dir", side_effect=PermissionError())
|
||||||
assert PackageSource.Auto.resolve("package") == PackageSource.AUR
|
assert PackageSource.Auto.resolve("package", repository_paths) == PackageSource.AUR
|
||||||
|
|
||||||
|
|
||||||
def test_resolve_directory(mocker: MockerFixture) -> None:
|
def test_resolve_directory(repository_paths: RepositoryPaths, mocker: MockerFixture) -> None:
|
||||||
"""
|
"""
|
||||||
must resolve auto type into the directory
|
must resolve auto type into the directory
|
||||||
"""
|
"""
|
||||||
mocker.patch("pathlib.Path.is_dir", return_value=True)
|
mocker.patch("pathlib.Path.is_dir", autospec=True, side_effect=lambda p: p == Path("path"))
|
||||||
mocker.patch("pathlib.Path.is_file", autospec=True, side_effect=_is_file_mock(False, False))
|
mocker.patch("pathlib.Path.is_file", autospec=True, side_effect=_is_file_mock(False, False))
|
||||||
assert PackageSource.Auto.resolve("path") == PackageSource.Directory
|
assert PackageSource.Auto.resolve("path", repository_paths) == PackageSource.Directory
|
||||||
|
|
||||||
|
|
||||||
def test_resolve_local(mocker: MockerFixture) -> None:
|
def test_resolve_local(repository_paths: RepositoryPaths, mocker: MockerFixture) -> None:
|
||||||
"""
|
"""
|
||||||
must resolve auto type into the local sources
|
must resolve auto type into the local sources
|
||||||
"""
|
"""
|
||||||
mocker.patch("pathlib.Path.is_dir", return_value=True)
|
mocker.patch("pathlib.Path.is_dir", return_value=False)
|
||||||
mocker.patch("pathlib.Path.is_file", autospec=True, side_effect=_is_file_mock(True, True))
|
mocker.patch("pathlib.Path.is_file", autospec=True, side_effect=_is_file_mock(True, True))
|
||||||
assert PackageSource.Auto.resolve("path") == PackageSource.Local
|
assert PackageSource.Auto.resolve("path", repository_paths) == PackageSource.Local
|
||||||
|
|
||||||
|
|
||||||
def test_resolve_remote(package_description_ahriman: PackageDescription, mocker: MockerFixture) -> None:
|
def test_resolve_local_cache(repository_paths: RepositoryPaths, mocker: MockerFixture) -> None:
|
||||||
|
"""
|
||||||
|
must resolve auto type into the local sources
|
||||||
|
"""
|
||||||
|
cache_mock = mocker.patch("ahriman.models.repository_paths.RepositoryPaths.cache_for", return_value=Path("cache"))
|
||||||
|
mocker.patch("pathlib.Path.is_dir", autospec=True, side_effect=lambda p: p == Path("cache"))
|
||||||
|
mocker.patch("pathlib.Path.is_file", autospec=True, side_effect=_is_file_mock(False, False))
|
||||||
|
|
||||||
|
assert PackageSource.Auto.resolve("path", repository_paths) == PackageSource.Local
|
||||||
|
cache_mock.assert_called_once_with("path")
|
||||||
|
|
||||||
|
|
||||||
|
def test_resolve_remote(package_description_ahriman: PackageDescription, repository_paths: RepositoryPaths,
|
||||||
|
mocker: MockerFixture) -> None:
|
||||||
"""
|
"""
|
||||||
must resolve auto type into the remote sources
|
must resolve auto type into the remote sources
|
||||||
"""
|
"""
|
||||||
mocker.patch("pathlib.Path.is_dir", return_value=False)
|
mocker.patch("pathlib.Path.is_dir", return_value=False)
|
||||||
mocker.patch("pathlib.Path.is_file", autospec=True, side_effect=_is_file_mock(False, False))
|
mocker.patch("pathlib.Path.is_file", autospec=True, side_effect=_is_file_mock(False, False))
|
||||||
assert PackageSource.Auto.resolve(f"https://host/{package_description_ahriman.filename}") == PackageSource.Remote
|
url = f"https://host/{package_description_ahriman.filename}"
|
||||||
|
assert PackageSource.Auto.resolve(url, repository_paths) == PackageSource.Remote
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
from pathlib import Path
|
import pytest
|
||||||
from pytest_mock import MockerFixture
|
|
||||||
|
|
||||||
from ahriman.models.package import Package
|
from pathlib import Path
|
||||||
|
|
||||||
|
from ahriman.core.exceptions import InitializeError
|
||||||
from ahriman.models.package_source import PackageSource
|
from ahriman.models.package_source import PackageSource
|
||||||
from ahriman.models.remote_source import RemoteSource
|
from ahriman.models.remote_source import RemoteSource
|
||||||
|
|
||||||
@ -20,6 +21,14 @@ def test_post_init(remote_source: RemoteSource) -> None:
|
|||||||
assert remote == remote_source
|
assert remote == remote_source
|
||||||
|
|
||||||
|
|
||||||
|
def test_is_remote() -> None:
|
||||||
|
"""
|
||||||
|
must correctly define if source is remote or not
|
||||||
|
"""
|
||||||
|
for source in PackageSource:
|
||||||
|
assert RemoteSource(source=source).is_remote or source not in (PackageSource.AUR, PackageSource.Repository)
|
||||||
|
|
||||||
|
|
||||||
def test_pkgbuild_dir(remote_source: RemoteSource) -> None:
|
def test_pkgbuild_dir(remote_source: RemoteSource) -> None:
|
||||||
"""
|
"""
|
||||||
must return path as is in `path` property
|
must return path as is in `path` property
|
||||||
@ -35,48 +44,16 @@ def test_from_json(remote_source: RemoteSource) -> None:
|
|||||||
assert RemoteSource.from_json(remote_source.view()) == remote_source
|
assert RemoteSource.from_json(remote_source.view()) == remote_source
|
||||||
|
|
||||||
|
|
||||||
def test_from_json_empty() -> None:
|
def test_git_source(remote_source: RemoteSource) -> None:
|
||||||
"""
|
"""
|
||||||
must return None in case of empty dictionary, which is required by the database wrapper
|
must correctly return git source
|
||||||
"""
|
"""
|
||||||
assert RemoteSource.from_json({}) is None
|
assert remote_source.git_source() == (remote_source.git_url, remote_source.branch)
|
||||||
|
|
||||||
|
|
||||||
def test_from_source_aur(package_ahriman: Package, mocker: MockerFixture) -> None:
|
def test_git_source_empty() -> None:
|
||||||
"""
|
"""
|
||||||
must construct remote from AUR source
|
must raise exception if path is none
|
||||||
"""
|
"""
|
||||||
remote_git_url_mock = mocker.patch("ahriman.core.alpm.remote.AUR.remote_git_url")
|
with pytest.raises(InitializeError):
|
||||||
remote_web_url_mock = mocker.patch("ahriman.core.alpm.remote.AUR.remote_web_url")
|
RemoteSource(source=PackageSource.Remote).git_source()
|
||||||
|
|
||||||
remote = RemoteSource.from_source(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_source_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.remote_git_url")
|
|
||||||
remote_web_url_mock = mocker.patch("ahriman.core.alpm.remote.Official.remote_web_url")
|
|
||||||
|
|
||||||
remote = RemoteSource.from_source(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(".")
|
|
||||||
assert remote.branch == "main"
|
|
||||||
assert remote.source == PackageSource.Repository
|
|
||||||
|
|
||||||
|
|
||||||
def test_from_source_other() -> None:
|
|
||||||
"""
|
|
||||||
must return None in case if source is not one of AUR or Repository
|
|
||||||
"""
|
|
||||||
assert RemoteSource.from_source(PackageSource.Archive, "package", "repository") is None
|
|
||||||
assert RemoteSource.from_source(PackageSource.Directory, "package", "repository") is None
|
|
||||||
assert RemoteSource.from_source(PackageSource.Local, "package", "repository") is None
|
|
||||||
assert RemoteSource.from_source(PackageSource.Remote, "package", "repository") is None
|
|
||||||
|
@ -48,7 +48,8 @@ target = gitremote
|
|||||||
target = gitremote
|
target = gitremote
|
||||||
|
|
||||||
[gitremote]
|
[gitremote]
|
||||||
commit_author = "user <user@host>"
|
commit_user = user
|
||||||
|
commit_email = user@host
|
||||||
push_url = https://github.com/arcan1s/repository.git
|
push_url = https://github.com/arcan1s/repository.git
|
||||||
pull_url = https://github.com/arcan1s/repository.git
|
pull_url = https://github.com/arcan1s/repository.git
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user