mirror of
https://github.com/arcan1s/ahriman.git
synced 2025-04-24 15:27:17 +00:00
fix issues with remote pull triggers (see #103)
* The issue appears when repository contains PKGBUILD in root. In this case it will copy tree with loosing package information, because the repository will be cloned to temporary path with random generated name * The issue appears when branch which is different from master is used for any reposittory with git files (e.g. single-pkgbuild repo or repo with submodules)
This commit is contained in:
parent
bd0f850d25
commit
237fec3f85
@ -27,6 +27,7 @@ from ahriman.core.configuration import Configuration
|
|||||||
from ahriman.core.exceptions import GitRemoteError
|
from ahriman.core.exceptions import GitRemoteError
|
||||||
from ahriman.core.log import LazyLogging
|
from ahriman.core.log import LazyLogging
|
||||||
from ahriman.core.util import walk
|
from ahriman.core.util import walk
|
||||||
|
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
|
from ahriman.models.remote_source import RemoteSource
|
||||||
|
|
||||||
@ -36,16 +37,18 @@ class RemotePull(LazyLogging):
|
|||||||
fetch PKGBUILDs from remote repository and use them for following actions
|
fetch PKGBUILDs from remote repository and use them for following actions
|
||||||
|
|
||||||
Attributes:
|
Attributes:
|
||||||
|
architecture(str): repository architecture
|
||||||
remote_source(RemoteSource): repository remote source (remote pull url and branch)
|
remote_source(RemoteSource): repository remote source (remote pull url and branch)
|
||||||
repository_paths(RepositoryPaths): repository paths instance
|
repository_paths(RepositoryPaths): repository paths instance
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, configuration: Configuration, section: str) -> None:
|
def __init__(self, configuration: Configuration, architecture: str, section: str) -> None:
|
||||||
"""
|
"""
|
||||||
default constructor
|
default constructor
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
configuration(Configuration): configuration instance
|
configuration(Configuration): configuration instance
|
||||||
|
architecture(str): repository architecture
|
||||||
section(str): settings section name
|
section(str): settings section name
|
||||||
"""
|
"""
|
||||||
self.remote_source = RemoteSource(
|
self.remote_source = RemoteSource(
|
||||||
@ -55,8 +58,30 @@ class RemotePull(LazyLogging):
|
|||||||
branch=configuration.get(section, "pull_branch", fallback="master"),
|
branch=configuration.get(section, "pull_branch", fallback="master"),
|
||||||
source=PackageSource.Local,
|
source=PackageSource.Local,
|
||||||
)
|
)
|
||||||
|
self.architecture = architecture
|
||||||
self.repository_paths = configuration.repository_paths
|
self.repository_paths = configuration.repository_paths
|
||||||
|
|
||||||
|
def package_copy(self, pkgbuild_path: Path) -> None:
|
||||||
|
"""
|
||||||
|
copy single PKGBUILD content to the repository tree
|
||||||
|
|
||||||
|
Args:
|
||||||
|
pkgbuild_path(Path): path to PKGBUILD to copy
|
||||||
|
"""
|
||||||
|
cloned_pkgbuild_dir = pkgbuild_path.parent
|
||||||
|
|
||||||
|
# load package from the PKGBUILD, because it might be possible that name doesn't match
|
||||||
|
# e.g. if we have just cloned repo with just one PKGBUILD
|
||||||
|
package = Package.from_build(cloned_pkgbuild_dir, self.architecture, None)
|
||||||
|
package_base = package.base
|
||||||
|
local_pkgbuild_dir = self.repository_paths.cache_for(package_base)
|
||||||
|
|
||||||
|
# copy source ignoring the git files
|
||||||
|
shutil.copytree(cloned_pkgbuild_dir, local_pkgbuild_dir,
|
||||||
|
ignore=shutil.ignore_patterns(".git*"), dirs_exist_ok=True)
|
||||||
|
# initialized git repository is required for local sources
|
||||||
|
Sources.init(local_pkgbuild_dir)
|
||||||
|
|
||||||
def repo_clone(self) -> None:
|
def repo_clone(self) -> None:
|
||||||
"""
|
"""
|
||||||
clone repository from remote source
|
clone repository from remote source
|
||||||
@ -74,11 +99,7 @@ class RemotePull(LazyLogging):
|
|||||||
clone_dir(Path): path to temporary cloned directory
|
clone_dir(Path): path to temporary cloned directory
|
||||||
"""
|
"""
|
||||||
for pkgbuild_path in filter(lambda path: path.name == "PKGBUILD", walk(clone_dir)):
|
for pkgbuild_path in filter(lambda path: path.name == "PKGBUILD", walk(clone_dir)):
|
||||||
cloned_pkgbuild_dir = pkgbuild_path.parent
|
self.package_copy(pkgbuild_path)
|
||||||
package_base = cloned_pkgbuild_dir.name
|
|
||||||
local_pkgbuild_dir = self.repository_paths.cache_for(package_base)
|
|
||||||
shutil.copytree(cloned_pkgbuild_dir, local_pkgbuild_dir, dirs_exist_ok=True)
|
|
||||||
Sources.init(local_pkgbuild_dir) # initialized git repository is required for local sources
|
|
||||||
|
|
||||||
def run(self) -> None:
|
def run(self) -> None:
|
||||||
"""
|
"""
|
||||||
|
@ -87,5 +87,5 @@ class RemotePullTrigger(Trigger):
|
|||||||
for target in self.targets:
|
for target in self.targets:
|
||||||
section, _ = self.configuration.gettype(
|
section, _ = self.configuration.gettype(
|
||||||
target, self.architecture, fallback=self.CONFIGURATION_SCHEMA_FALLBACK)
|
target, self.architecture, fallback=self.CONFIGURATION_SCHEMA_FALLBACK)
|
||||||
runner = RemotePull(self.configuration, section)
|
runner = RemotePull(self.configuration, self.architecture, section)
|
||||||
runner.run()
|
runner.run()
|
||||||
|
@ -79,6 +79,7 @@ class RemotePush(LazyLogging):
|
|||||||
package_target_dir = target_dir / package.base
|
package_target_dir = target_dir / package.base
|
||||||
shutil.rmtree(package_target_dir, ignore_errors=True)
|
shutil.rmtree(package_target_dir, ignore_errors=True)
|
||||||
# ...secondly, we clone whole tree...
|
# ...secondly, we clone whole tree...
|
||||||
|
# fetch is used intentionally here in order to avoid copying downloaded blobs
|
||||||
Sources.fetch(package_target_dir, package.remote)
|
Sources.fetch(package_target_dir, package.remote)
|
||||||
# ...and last, but not least, we remove the dot-git directory...
|
# ...and last, but not least, we remove the dot-git directory...
|
||||||
for git_file in package_target_dir.glob(".git*"):
|
for git_file in package_target_dir.glob(".git*"):
|
||||||
|
@ -7,6 +7,7 @@ from unittest.mock import call as MockCall
|
|||||||
from ahriman.core.configuration import Configuration
|
from ahriman.core.configuration import Configuration
|
||||||
from ahriman.core.exceptions import GitRemoteError
|
from ahriman.core.exceptions import GitRemoteError
|
||||||
from ahriman.core.gitremote.remote_pull import RemotePull
|
from ahriman.core.gitremote.remote_pull import RemotePull
|
||||||
|
from ahriman.models.package import Package
|
||||||
|
|
||||||
|
|
||||||
def test_repo_clone(configuration: Configuration, mocker: MockerFixture) -> None:
|
def test_repo_clone(configuration: Configuration, mocker: MockerFixture) -> None:
|
||||||
@ -15,36 +16,53 @@ def test_repo_clone(configuration: Configuration, mocker: MockerFixture) -> None
|
|||||||
"""
|
"""
|
||||||
fetch_mock = mocker.patch("ahriman.core.build_tools.sources.Sources.fetch")
|
fetch_mock = mocker.patch("ahriman.core.build_tools.sources.Sources.fetch")
|
||||||
copy_mock = mocker.patch("ahriman.core.gitremote.remote_pull.RemotePull.repo_copy")
|
copy_mock = mocker.patch("ahriman.core.gitremote.remote_pull.RemotePull.repo_copy")
|
||||||
runner = RemotePull(configuration, "gitremote")
|
runner = RemotePull(configuration, "x86_64", "gitremote")
|
||||||
|
|
||||||
runner.repo_clone()
|
runner.repo_clone()
|
||||||
fetch_mock.assert_called_once_with(pytest.helpers.anyvar(int), runner.remote_source)
|
fetch_mock.assert_called_once_with(pytest.helpers.anyvar(int), runner.remote_source)
|
||||||
copy_mock.assert_called_once_with(pytest.helpers.anyvar(int))
|
copy_mock.assert_called_once_with(pytest.helpers.anyvar(int))
|
||||||
|
|
||||||
|
|
||||||
|
def test_package_copy(configuration: Configuration, package_ahriman: Package, mocker: MockerFixture) -> None:
|
||||||
|
"""
|
||||||
|
must copy single package
|
||||||
|
"""
|
||||||
|
package_mock = mocker.patch("ahriman.models.package.Package.from_build", return_value=package_ahriman)
|
||||||
|
patterns = object()
|
||||||
|
ignore_patterns_mock = mocker.patch("shutil.ignore_patterns", return_value=patterns)
|
||||||
|
copytree_mock = mocker.patch("shutil.copytree")
|
||||||
|
init_mock = mocker.patch("ahriman.core.build_tools.sources.Sources.init")
|
||||||
|
runner = RemotePull(configuration, "x86_64", "gitremote")
|
||||||
|
local = Path("local")
|
||||||
|
|
||||||
|
runner.package_copy(local / "PKGBUILD")
|
||||||
|
package_mock.assert_called_once_with(local, "x86_64", None)
|
||||||
|
ignore_patterns_mock.assert_called_once_with(".git*")
|
||||||
|
copytree_mock.assert_called_once_with(
|
||||||
|
local, configuration.repository_paths.cache_for(package_ahriman.base),
|
||||||
|
ignore=patterns, dirs_exist_ok=True)
|
||||||
|
init_mock.assert_called_once_with(configuration.repository_paths.cache_for(package_ahriman.base))
|
||||||
|
|
||||||
|
|
||||||
def test_repo_copy(configuration: Configuration, mocker: MockerFixture) -> None:
|
def test_repo_copy(configuration: Configuration, mocker: MockerFixture) -> None:
|
||||||
"""
|
"""
|
||||||
must copy repository tree from temporary directory to the local cache
|
must copy repository tree from temporary directory to the local cache
|
||||||
"""
|
"""
|
||||||
|
local = Path("local")
|
||||||
mocker.patch("ahriman.core.gitremote.remote_pull.walk", return_value=[
|
mocker.patch("ahriman.core.gitremote.remote_pull.walk", return_value=[
|
||||||
Path("local") / "package1" / "PKGBUILD",
|
local / "package1" / "PKGBUILD",
|
||||||
Path("local") / "package1" / ".SRCINFO",
|
local / "package1" / ".SRCINFO",
|
||||||
Path("local") / "package2" / ".SRCINFO",
|
local / "package2" / ".SRCINFO",
|
||||||
Path("local") / "package3" / "PKGBUILD",
|
local / "package3" / "PKGBUILD",
|
||||||
Path("local") / "package3" / ".SRCINFO",
|
local / "package3" / ".SRCINFO",
|
||||||
])
|
])
|
||||||
copytree_mock = mocker.patch("shutil.copytree")
|
copy_mock = mocker.patch("ahriman.core.gitremote.remote_pull.RemotePull.package_copy")
|
||||||
init_mock = mocker.patch("ahriman.core.build_tools.sources.Sources.init")
|
runner = RemotePull(configuration, "x86_64", "gitremote")
|
||||||
runner = RemotePull(configuration, "gitremote")
|
|
||||||
|
|
||||||
runner.repo_copy(Path("local"))
|
runner.repo_copy(local)
|
||||||
copytree_mock.assert_has_calls([
|
copy_mock.assert_has_calls([
|
||||||
MockCall(Path("local") / "package1", configuration.repository_paths.cache_for("package1"), dirs_exist_ok=True),
|
MockCall(local / "package1" / "PKGBUILD"),
|
||||||
MockCall(Path("local") / "package3", configuration.repository_paths.cache_for("package3"), dirs_exist_ok=True),
|
MockCall(local / "package3" / "PKGBUILD"),
|
||||||
])
|
|
||||||
init_mock.assert_has_calls([
|
|
||||||
MockCall(configuration.repository_paths.cache_for("package1")),
|
|
||||||
MockCall(configuration.repository_paths.cache_for("package3")),
|
|
||||||
])
|
])
|
||||||
|
|
||||||
|
|
||||||
@ -53,7 +71,7 @@ def test_run(configuration: Configuration, mocker: MockerFixture) -> None:
|
|||||||
must clone repo on run
|
must clone repo on run
|
||||||
"""
|
"""
|
||||||
clone_mock = mocker.patch("ahriman.core.gitremote.remote_pull.RemotePull.repo_clone")
|
clone_mock = mocker.patch("ahriman.core.gitremote.remote_pull.RemotePull.repo_clone")
|
||||||
runner = RemotePull(configuration, "gitremote")
|
runner = RemotePull(configuration, "x86_64", "gitremote")
|
||||||
|
|
||||||
runner.run()
|
runner.run()
|
||||||
clone_mock.assert_called_once_with()
|
clone_mock.assert_called_once_with()
|
||||||
@ -64,7 +82,7 @@ def test_run_failed(configuration: Configuration, mocker: MockerFixture) -> None
|
|||||||
must reraise exception on error occurred
|
must reraise exception on error occurred
|
||||||
"""
|
"""
|
||||||
mocker.patch("ahriman.core.gitremote.remote_pull.RemotePull.repo_clone", side_effect=Exception())
|
mocker.patch("ahriman.core.gitremote.remote_pull.RemotePull.repo_clone", side_effect=Exception())
|
||||||
runner = RemotePull(configuration, "gitremote")
|
runner = RemotePull(configuration, "x86_64", "gitremote")
|
||||||
|
|
||||||
with pytest.raises(GitRemoteError):
|
with pytest.raises(GitRemoteError):
|
||||||
runner.run()
|
runner.run()
|
||||||
|
Loading…
Reference in New Issue
Block a user