Skip to content

Commit

Permalink
Add patches direct in yaml
Browse files Browse the repository at this point in the history
  • Loading branch information
mt-software-de committed Jan 7, 2025
1 parent b2f19f8 commit c80c33b
Show file tree
Hide file tree
Showing 5 changed files with 135 additions and 18 deletions.
2 changes: 2 additions & 0 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -353,11 +353,13 @@ Contributors
* Simone Orsi (camptocamp_)
* Artem Kostyuk
* Jan Verbeek
* Michael Tietz (MT_Software_)

.. _ACSONE: https://www.acsone.eu
.. _Tecnativa: https://www.tecnativa.com
.. _camptocamp: https://www.camptocamp.com
.. _LasLabs: https://laslabs.com
.. _MT_Software: https://github.com/mt-software-de

Maintainer
----------
Expand Down
31 changes: 31 additions & 0 deletions git_aggregator/command.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# © 2015 ACSONE SA/NV
# Copyright 2023 Michael Tietz (MT Software) <mtietz@mt-software.de>
# License AGPLv3 (http://www.gnu.org/licenses/agpl-3.0-standalone.html)
# Parts of the code comes from ANYBOX
# https://github.com/anybox/anybox.recipe.odoo
import logging
import subprocess

from ._compat import console_to_str

logger = logging.getLogger(__name__)


class CommandExecutor:
def __init__(self, cwd):
self.cwd = cwd

def log_call(self, cmd, callwith=subprocess.check_call,
log_level=logging.DEBUG, **kw):
"""Wrap a subprocess call with logging
:param meth: the calling method to use.
"""
logger.log(log_level, "%s> call %r", self.cwd, cmd)
try:
ret = callwith(cmd, **kw)
except Exception:
logger.error("%s> error calling %r", self.cwd, cmd)
raise
if callwith == subprocess.check_output:
ret = console_to_str(ret)
return ret
12 changes: 12 additions & 0 deletions git_aggregator/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,21 @@

from ._compat import string_types
from .exception import ConfigException
from .patch import Patches

log = logging.getLogger(__name__)


def update_patches(repo_dict, repo_data):
"""Check and update repo_dict with patch files"""
patches_data = repo_data.get("patches")
patches = repo_dict.setdefault("patches", Patches())
if not patches_data:
return
for patch in patches_data:
patches += Patches.prepare_patches(patch, repo_dict.get("cwd"))


def get_repos(config, force=False):
"""Return a :py:obj:`list` list of repos from config file.
:param config: the repos config in :py:class:`dict` format.
Expand Down Expand Up @@ -126,6 +137,7 @@ def get_repos(config, force=False):
cmds = [cmds]
commands = cmds
repo_dict['shell_command_after'] = commands
update_patches(repo_dict, repo_data)
repo_list.append(repo_dict)
return repo_list

Expand Down
66 changes: 66 additions & 0 deletions git_aggregator/patch.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
# Copyright 2023 Michael Tietz (MT Software) <mtietz@mt-software.de>
# License AGPLv3 (http://www.gnu.org/licenses/agpl-3.0-standalone.html)
import logging
import subprocess
from pathlib import Path

from .command import CommandExecutor

logger = logging.getLogger(__name__)


class Patch(CommandExecutor):
is_local = False

def __init__(self, path, cwd):
super().__init__(cwd)
self.path = path
path = Path(path)
if path.exists():
self.is_local = True

def retrive_data(self):
path = self.path
if self.is_local:
patch_path = Path(path).absolute()
path = f"FILE:{str(patch_path)}"
cmd = [
"curl",
path,
]
if logger.getEffectiveLevel() != logging.DEBUG:
cmd.append('-s')
return self.log_call(
cmd,
callwith=subprocess.Popen,
stdout=subprocess.PIPE
)

def apply(self):
res = self.retrive_data()
cmd = [
"git",
"am",
]
if logger.getEffectiveLevel() != logging.DEBUG:
cmd.append('--quiet')
self.log_call(cmd, cwd=self.cwd, stdin=res.stdout)


class Patches(list):
"""List of patches"""
@staticmethod
def prepare_patches(path, cwd):
_path = Path(path)
patches = Patches()
if not _path.exists() or _path.is_file():
patches.append(Patch(path, cwd))
elif _path.is_dir():
for fpath in _path.iterdir():
if fpath.is_file():
patches.append(Patch(str(fpath), cwd))
return patches

def apply(self):
for patch in self:
patch.apply()
42 changes: 24 additions & 18 deletions git_aggregator/repo.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import requests

from ._compat import console_to_str
from .command import CommandExecutor
from .exception import DirtyException, GitAggregatorException

FETCH_DEFAULTS = ("depth", "shallow-since", "shallow-exclude")
Expand All @@ -30,13 +31,13 @@ def ishex(s):
return True


class Repo:
class Repo(CommandExecutor):

_git_version = None

def __init__(self, cwd, remotes, merges, target,
shell_command_after=None, fetch_all=False, defaults=None,
force=False):
force=False, patches=None):
"""Initialize a git repository aggregator
:param cwd: path to the directory where to initialize the repository
Expand All @@ -56,7 +57,7 @@ def __init__(self, cwd, remotes, merges, target,
:param bool force:
When ``False``, it will stop if repo is dirty.
"""
self.cwd = cwd
super().__init__(cwd)
self.remotes = remotes
if fetch_all is True:
self.fetch_all = frozenset(r["name"] for r in remotes)
Expand All @@ -67,6 +68,7 @@ def __init__(self, cwd, remotes, merges, target,
self.shell_command_after = shell_command_after or []
self.defaults = defaults or dict()
self.force = force
self.patches = patches

@property
def git_version(self):
Expand Down Expand Up @@ -148,21 +150,6 @@ def query_remote_ref(self, remote, ref):
return 'HEAD', sha
return None, ref

def log_call(self, cmd, callwith=subprocess.check_call,
log_level=logging.DEBUG, **kw):
"""Wrap a subprocess call with logging
:param meth: the calling method to use.
"""
logger.log(log_level, "%s> call %r", self.cwd, cmd)
try:
ret = callwith(cmd, **kw)
except Exception:
logger.error("%s> error calling %r", self.cwd, cmd)
raise
if callwith == subprocess.check_output:
ret = console_to_str(ret)
return ret

def aggregate(self):
""" Aggregate all merges into the target branch
If the target_dir doesn't exist, create an empty git repo otherwise
Expand All @@ -187,6 +174,7 @@ def aggregate(self):
self._reset_to(origin["remote"], origin["ref"])
for merge in merges:
self._merge(merge)
self.patches.apply()
self._execute_shell_command_after()
logger.info('End aggregation of %s', self.cwd)

Expand Down Expand Up @@ -313,6 +301,24 @@ def _merge(self, merge):
cmd += self._fetch_options(merge) + (merge["remote"], merge["ref"])
self.log_call(cmd, cwd=self.cwd)

def _patch(self, patch_path):
cmd = (
"patch",
"-p1",
"--no-backup-if-mismatch",
"-t",
"-i",
str(patch_path.resolve()),
)
if logger.getEffectiveLevel() != logging.DEBUG:
cmd += ('--quiet',)
self.log_call(cmd, cwd=self.cwd)
self.log_call(("git", "add", "."), cwd=self.cwd)
self.log_call(
("git", "commit", "-am", "Applied patch %s" % str(patch_path)),
cwd=self.cwd,
)

def _get_remotes(self):
lines = self.log_call(
['git', 'remote', '-v'],
Expand Down

0 comments on commit c80c33b

Please sign in to comment.