Script 'mail_helper' called by obssrc
Hello community,
here is the log from the commit of package ansible-sap-operations for
openSUSE:Factory checked in at 2025-08-12 17:05:21
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/ansible-sap-operations (Old)
and /work/SRC/openSUSE:Factory/.ansible-sap-operations.new.1085 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "ansible-sap-operations"
Tue Aug 12 17:05:21 2025 rev:2 rq:1298993 version:0.9.1
Changes:
--------
---
/work/SRC/openSUSE:Factory/ansible-sap-operations/ansible-sap-operations.changes
2025-04-20 19:49:32.406810169 +0200
+++
/work/SRC/openSUSE:Factory/.ansible-sap-operations.new.1085/ansible-sap-operations.changes
2025-08-12 17:07:04.777539294 +0200
@@ -1,0 +2,6 @@
+Tue Aug 12 07:16:19 UTC 2025 - Marcel Mamula <[email protected]>
+
+- Remove unsupported Ansible Roles
+- Add updated README.md
+
+-------------------------------------------------------------------
Old:
----
collection_update.py
New:
----
README.md
transformation.py
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ ansible-sap-operations.spec ++++++
--- /var/tmp/diff_new_pack.vbaMSd/_old 2025-08-12 17:07:05.969589088 +0200
+++ /var/tmp/diff_new_pack.vbaMSd/_new 2025-08-12 17:07:05.977589423 +0200
@@ -26,8 +26,9 @@
Release: 0
URL: https://github.com/SUSE/community.sap_operations/
Source0:
%{url}archive/refs/tags/%{version}.tar.gz#/%{name}-%{version}.tar.gz
-Source1: ansible-sap-operations.yaml
-Source2: collection_update.py
+Source1: %{name}.yaml
+Source2: transformation.py
+Source3: README.md
BuildArch: noarch
@@ -40,7 +41,6 @@
# Python module ruamel.yaml for collection-update.py
BuildRequires: python3-ruamel.yaml
-
%description
This package provides a Ansible collection suse.sap_operations.
@@ -49,23 +49,18 @@
This collection can be used to execute sapcontrol functions,
update SAP profiles, configure firewall rules, execute RFC, etc.
-
%prep
-# Extract tarball
-cd %{_builddir}
-tar -xzf %{_sourcedir}/%{name}-%{version}.tar.gz --strip-components=1
-
-# Execute python script to update documentation and remove unsupported roles
-python3 %{_sourcedir}/collection_update.py --config %{_sourcedir}/%{name}.yaml
--build_dir %{_builddir}
-
+%autosetup -p1 -n community.%{ansible_collection_name}-%{version}
+# Update readme file
+install -m 644 %{SOURCE3} README.md
%build
+# Execute python script to update documentation and remove unsupported roles
+python3 %{_sourcedir}/transformation.py --config %{_sourcedir}/%{name}.yaml
--build_dir .
# Build the Ansible collection
ansible-galaxy collection build --output-path %{_builddir}
-
%install
-rm -rf %{buildroot}
mkdir -p %{buildroot}%{_datadir}/ansible/collections
mkdir -p %{buildroot}%{_datadir}/ansible/roles/
@@ -73,9 +68,8 @@
ansible-galaxy collection install --force
%{_builddir}/suse-%{ansible_collection_name}-%{version}.tar.gz \
--collections-path %{buildroot}%{_datadir}/ansible/collections
-
%post
-# Loop through roles in collection and create symlinks under
%{_datadir}/ansible/roles/
+# Loop through roles in collection and create symlinks under
/usr/share/ansible/roles/
# Installed community collection will take precedence over role symlinks.
for role in %{ansible_collection_path}/roles/*; do
role_name=$(basename "$role")
@@ -85,9 +79,8 @@
fi
done
-
%postun
-# Loop through roles in %{_datadir}/ansible/roles/ and remove those that link
to collection
+# Loop through roles in /usr/share/ansible/roles/ and remove those that link
to collection
if [ "$1" -eq 0 ]; then
for role in
%{_datadir}/ansible/roles/community.%{ansible_collection_name}.*; do
if [ -L "$role" ]; then
@@ -99,9 +92,7 @@
done
fi
-
%files
%{_datadir}/ansible/collections/
%{_datadir}/ansible/roles/
-
++++++ README.md ++++++
# suse.sap_operations Ansible Collection
## Description
This Ansible Collection executes various day-to-day operation tasks for SAP
Systems.
## Requirements
### Control Nodes
Operating system:
- Any operating system with required Python and Ansible versions.
Python: 3.11 or higher
Ansible-core: 2.18 or higher
### Managed Nodes
Operating system:
- SUSE Linux Enterprise Server for SAP applications 15 SP5+ (SLE4SAP)
- Red Hat Enterprise Linux for SAP Solutions 8.x 9.x (RHEL4SAP)
**NOTE: Operating system needs to have access to required package repositories
either directly or via subscription registration.**
Python: 3.11 or higher
## Use Cases
### Example Scenarios
- Operate `sapcontrol` functions like starting whole SAP System, stopping, etc.
- Update SAP profile files
### Ansible Roles
| Name | Summary |
| :--- | :--- |
| [sap_control](/roles/sap_control) | Operate sapcontrol tool (e.g. start,
stop, etc.) |
| [sap_profile_update](/roles/sap_profile_update) | Update SAP System profiles
(default or instance) |
## Testing
This Ansible Collection was tested across different Operating Systems, SAP
products and scenarios. You can find examples of some of them below.
Operating systems:
- SUSE Linux Enterprise Server for SAP applications 15 SP5+ (SLE4SAP)
- Red Hat Enterprise Linux for SAP Solutions 8.x 9.x (RHEL4SAP)
## Contributing
You can find more information about ways you can contribute at [sap-linuxlab
website](https://sap-linuxlab.github.io/initiative_contributions/).
## Support
You can report any issues using
[Issues](https://github.com/SUSE/community.sap_operations/issues) section.
## Release Notes and Roadmap
You can find the release notes of this collection in [Changelog
file](https://github.com/SUSE/community.sap_operations/blob/main/CHANGELOG.rst)
## Further Information
### Variable Precedence Rules
Please follow [Ansible Precedence
guidelines](https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_variables.html#variable-precedence-where-should-i-put-a-variable)
on how to pass variables when using this collection.
## License
[Apache
2.0](https://github.com/SUSE/community.sap_operations/blob/main/LICENSE)
(No newline at EOF)
++++++ ansible-sap-operations.yaml ++++++
--- /var/tmp/diff_new_pack.vbaMSd/_old 2025-08-12 17:07:06.053592597 +0200
+++ /var/tmp/diff_new_pack.vbaMSd/_new 2025-08-12 17:07:06.061592932 +0200
@@ -1,12 +1,13 @@
-# Configuration file for collection changes before build.
-# Collection: community.sap_operations
+# Configuration file for changes before build.
-# Types of changes used by collection_update.py
-# remove_paths - Remove specific directories and files that are no longer
needed.
-# remove_lines - Remove specific lines containing certain patterns from files.
-# replace_text - Replace specific text strings within files.
-# update_yaml_key - Update specific keys in YAML files with new values.
-# append_yaml_list - Append items to a list in a YAML file.
+# Types of available options for transformation:
+# - remove_paths - Removes the specified files or directories.
+# - remove_lines - Removes lines matching the patterns from the files matching
specified glob patterns.
+# - replace_text - Replaces text in files matching specified glob patterns.
+# - update_yaml_key - Updates a specific key's value in the specified YAML
files matching specified glob patterns.
+# - append_yaml_list - Appends a new item to a list in the specified YAML
files matching specified glob patterns.
+# - set_yaml_value - Sets or replaces a specific key's value in the specified
YAML files matching specified glob patterns.
+# - remove_yaml_list_items - Removes specific items from a list in the
specified YAML files matching specified glob patterns.
changes:
# Main collection changes
@@ -15,32 +16,47 @@
# Remove all unsupported roles.
# Remove all 'meta/main.yml' files within any role directory.
paths:
- - "roles/sap_rhsm"
- - "roles/sap_fapolicy"
+ - "roles/os_ansible_user" # non-SAP
+ - "roles/os_etchosts" # non-SAP
+ - "roles/os_knownhosts" # non-SAP
+ - "roles/sap_fapolicy" # non-SUSE
+ - "roles/sap_firewall" # obsolete, replaced with posix and LSR
+ - "roles/sap_hana_backint" # TODO: Add after rework
+ - "roles/sap_hana_sr_takeover" # TODO: Add after rework
+ - "roles/sap_rfc" # TODO: Add after rework
+ - "roles/sap_rhsm" # non-SUSE
- "roles/*/meta/main.yml"
- type: remove_lines
# Remove specific lines from README.md and all role README.md files.
# This is used to clean up any mention of unsupported roles and leftover
Ansible Lint markers.
files:
- - "README.md"
+ # - "README.md"
- "roles/*/README.md"
patterns:
- - "sap_rhsm"
- - "sap_fapolicy"
+ # - "sap_rhsm"
+ # - "sap_fapolicy"
- "\\[Ansible Lint"
+ - 'param: "all"'
- type: replace_text
# Replace specific text strings in galaxy.yml and README.md files.
# This is used to update the namespace and repository links from
'community' to 'suse'.
files:
- "galaxy.yml"
- - "README.md"
+ # - "README.md"
replacements:
- { find: "namespace: community", replace: "namespace: suse" }
- { find: "github.com/sap-linuxlab/community", replace:
"github.com/SUSE/community" }
- { find: "documentation:.*", replace: "documentation:
https://github.com/SUSE/community.sap_operations/blob/main/README.md" }
+ - type: replace_text
+ # Replace obsolete plugin with sap_libs
+ files:
+ - "roles/*/README.md"
+ replacements:
+ - { find: "community.sap_operations.sap_facts:", replace:
"community.sap_libs.sap_system_facts:" }
+
- type: update_yaml_key
# Update the 'authors' key in galaxy.yml to 'SUSE'.
files:
@@ -57,10 +73,21 @@
key: "build_ignore"
value:
- "tests"
+ - "roles/*/tests"
- ".git*"
+ - "*/.git*"
+ - "*/*/.git*"
- ".ansible-lint"
+ - "*/*/.ansible-lint"
- ".yamllint*"
+ - "*/*/.yamllint*"
- ".pylintrc*"
- "bindep*"
- ".pre-commit-config.yaml"
+ - "changelogs/.plugin-cache.yaml"
+ - "changelogs/fragments"
+ - "plugins"
+ - "docs/module*"
+ - "playbooks"
+(No newline at EOF)
++++++ transformation.py ++++++
# This Python script updates upstream with downstream customizations before
packaging.
# All customizations are defined in separate yaml file.
# List of available customizations:
# - remove_paths - Removes the specified files or directories.
# - remove_lines - Removes lines matching the patterns from the files matching
specified glob patterns.
# - replace_text - Replaces text in files matching specified glob patterns.
# - update_yaml_key - Updates a specific key's value in the specified YAML
files matching specified glob patterns.
# - append_yaml_list - Appends a new item to a list in the specified YAML files
matching specified glob patterns.
# - set_yaml_value - Sets or replaces a specific key's value in the specified
YAML files matching specified glob patterns.
# - remove_yaml_list_items - Removes specific items from a list in the
specified YAML files matching specified glob patterns.
# Intended use: Executed by spec file during %prep
import os
import shutil
import re
import glob
import argparse
# Requires entry in spec file: BuildRequires: python3-ruamel.yaml
from ruamel.yaml import YAML
yaml = YAML()
yaml.preserve_quotes = True # Preserves quotes
yaml.indent(mapping=2, sequence=4, offset=2) # Preserves indents in yaml
yaml.width = 4096 # Disable ruamel wrapping long lines
def load_config(config_file):
"""Loads the configuration from a YAML file.
"""
with open(config_file, 'r') as f:
return yaml.load(f)
def remove_paths(build_dir, paths):
"""Removes the specified files or directories.
This function iterates through a list of path patterns, finds all matching
files and directories using glob, and removes them. This is useful for
cleaning up a build directory by removing unnecessary files or directories
before packaging.
Args:
build_dir (str): The absolute path to the base directory from which
paths will be removed.
paths (list[str]): A list of path patterns to remove. These paths are
relative to `build_dir` and can include glob patterns (e.g.,
'*.txt',
'temp/**').
Example:
```yaml
changes:
- type: remove_paths
paths:
- "roles/*/meta/main.yml"
```
"""
for path_pattern in paths:
full_pattern = os.path.join(build_dir, path_pattern)
for item in glob.glob(full_pattern):
relative_path = os.path.relpath(item, build_dir)
if os.path.isdir(item):
print(f"Removed: {relative_path}")
shutil.rmtree(item, ignore_errors=True)
elif os.path.isfile(item):
print(f"Removed: {relative_path}")
os.remove(item)
def remove_lines(build_dir, files_patterns, patterns):
"""Removes lines matching the patterns from the files matching specified
glob patterns.
This function finds files matching the given glob patterns and then reads
each file to remove any lines that match any of the specified regular
expression patterns. This is useful for cleaning up documentation or
configuration files by removing obsolete or unwanted content.
Args:
build_dir (str): The absolute path to the base directory where the
files are located.
files_patterns (list[str]): A list of file path patterns to process.
These paths are relative to `build_dir` and support glob
patterns (e.g., 'docs/*.md', 'roles/**/tasks/main.yml').
patterns (list[str]): A list of regular expression patterns. Any line
in the target files that matches one of these patterns will be
removed.
Example:
```yaml
changes:
- type: remove_lines
files:
- "README.md"
- "roles/*/README.md"
patterns:
- "\\[Ansible Lint"
```
"""
for file_pattern in files_patterns:
full_pattern = os.path.join(build_dir, file_pattern)
for file_path in glob.glob(full_pattern):
if os.path.isfile(file_path):
relative_path = os.path.relpath(file_path, build_dir)
with open(file_path, 'r') as f:
lines = f.readlines()
updated_lines = [
line
for line in lines
if not any(re.search(pattern, line) for pattern in patterns)
]
with open(file_path, 'w') as f:
f.writelines(updated_lines)
print(f"Removed lines from: {relative_path}")
def replace_text(build_dir, files_patterns, replacements):
"""Replaces text in files matching specified glob patterns.
This function finds all files matching the given patterns and performs a
series of find-and-replace operations on their content. The 'find'
patterns are treated as regular expressions, allowing for powerful and
flexible text manipulation. This is useful for updating project-wide
values like namespaces, repository URLs, or other boilerplate text.
Args:
build_dir (str): The absolute path to the base directory where the
files are located.
files_patterns (list[str]): A list of file path patterns to process.
These paths are relative to `build_dir` and support glob
patterns (e.g., 'README.md', 'roles/**/*.yml').
replacements (list[dict[str, str]]): A list of replacement rules.
Each rule is a dictionary with two keys:
- 'find': The regular expression pattern to search for.
- 'replace': The string to substitute for each match.
Example:
```yaml
changes:
- type: replace_text
files:
- "galaxy.yml"
replacements:
- { find: "namespace: community", replace: "namespace: suse" }
```
"""
for file_pattern in files_patterns:
full_pattern = os.path.join(build_dir, file_pattern)
for file_path in glob.glob(full_pattern):
if os.path.isfile(file_path):
relative_path = os.path.relpath(file_path, build_dir)
with open(file_path, 'r') as f:
content = f.read()
for replacement in replacements:
content = re.sub(
replacement['find'],
replacement['replace'],
content,
flags=re.MULTILINE,
)
with open(file_path, 'w') as f:
f.write(content)
print(
f"Replaced text {replacement['find']} with
{replacement['replace']} in: {relative_path}"
)
def read_yaml_header(file_path):
"""Reads the header of a YAML file (lines before the first '---').
Args:
file_path (str): The path to the YAML file.
Returns:
list: A list of lines representing the header of the YAML file.
"""
header_lines = []
with open(file_path, 'r') as f:
for line in f:
if line.strip() == '---':
header_lines.append(line)
break
header_lines.append(line)
return header_lines
def update_yaml_key(build_dir, files_patterns, key_path, value):
"""Updates a specific key's value in the specified YAML files, preserving
the header.
This function finds all YAML files matching the given patterns and updates
the value of a specified key. The key can be nested, using dot notation
for the path (e.g., 'parent.child.key'). If the key or any part of its
path does not exist, it will be created.
The function is designed to preserve YAML formatting, including comments
and indentation, by using `ruamel.yaml` and by explicitly handling
non-YAML headers (lines before the first '---').
Args:
build_dir (str): The absolute path to the base directory where the
YAML files are located.
files_patterns (list[str]): A list of file path patterns to process,
relative to `build_dir`. Supports glob patterns (e.g., 'galaxy.yml',
'roles/**/meta.yml').
key_path (str): The dot-separated path to the key to update
(e.g., 'info.version', 'authors').
value (any): The new value to assign to the key. This can be any
YAML-compatible type (string, list, dictionary, etc.).
Example:
```yaml
changes:
- type: update_yaml_key
files:
- "galaxy.yml"
key: "build_ignore"
value:
- "tests"
```
"""
for file_pattern in files_patterns:
full_pattern = os.path.join(build_dir, file_pattern)
for file_path in glob.glob(full_pattern):
if os.path.exists(file_path):
try:
relative_path = os.path.relpath(file_path, build_dir)
header_lines = read_yaml_header(file_path)
with open(file_path, 'r') as f:
# Skip header lines when loading
for _ in header_lines:
next(f, None)
data = yaml.load(f)
keys = key_path.split('.')
current_level = data
for i, key in enumerate(keys):
if i == len(keys) - 1:
if key not in current_level:
print(
f"Warning: Key '{key_path}' not found in
{relative_path}"
)
else:
current_level[key] = value
print(f"Updated key '{key_path}' in:
{relative_path}")
else:
if key not in current_level:
current_level[key] = {}
print(
f"Created missing key '{key}' in path
'{key_path}' in: {relative_path}"
)
current_level = current_level[key]
with open(file_path, 'w') as f:
f.writelines(header_lines)
yaml.dump(data, f)
except Exception as e:
print(f"Error processing YAML in {relative_path}: {e}")
def append_yaml_list(build_dir, files_patterns, list_key_path, new_item):
"""Appends a new item to a list in the specified YAML files, preserving the
header.
This function finds all YAML files matching the given patterns and appends
a new item to a specified list. The list is identified by a dot-separated
key path. If the list or any part of its path does not exist, it will be
created. The function ensures the item is not added if it already exists
in the list, preventing duplicates.
Like other YAML modification functions in this script, it preserves
comments and formatting by using `ruamel.yaml` and handling file headers.
Args:
build_dir (str): The absolute path to the base directory where the
YAML files are located.
files_patterns (list[str]): A list of file path patterns to process,
relative to `build_dir`. Supports glob patterns.
list_key_path (str): The dot-separated path to the list to which the
item will be appended (e.g., 'galaxy_info.platforms').
new_item (any): The item to append to the list. This can be a simple
string or a more complex dictionary.
Example:
```yaml
changes:
- type: append_yaml_list
files:
- "roles/*/meta/main.yml"
list_key: "galaxy_info.platforms"
new_item:
name: "SLES"
versions:
- "15"
```
"""
for file_pattern in files_patterns:
full_pattern = os.path.join(build_dir, file_pattern)
for file_path in glob.glob(full_pattern):
if os.path.exists(file_path):
try:
relative_path = os.path.relpath(file_path, build_dir)
header_lines = read_yaml_header(file_path)
with open(file_path, 'r') as f:
# Skip header lines when loading
for _ in header_lines:
next(f, None)
data = yaml.load(f)
keys = list_key_path.split('.')
current_level = data
for i, key in enumerate(keys):
if i == len(keys) - 1:
if key not in current_level:
current_level[key] = []
print(
f"Created missing list '{list_key_path}'
in: {relative_path}"
)
if isinstance(current_level[key], list):
if new_item not in current_level[key]:
current_level[key].append(new_item)
print(
f"Appended item to list
'{list_key_path}' in: {relative_path}"
)
else:
print(
f"Item '{new_item}' already exists in
list '{list_key_path}' in: {relative_path}"
)
else:
if key not in current_level:
current_level[key] = {}
print(
f"Created missing key '{key}' in path
'{list_key_path}' in: {relative_path}"
)
current_level = current_level[key]
with open(file_path, 'w') as f:
f.writelines(header_lines)
yaml.dump(data, f)
except Exception as e:
print(f"Error processing YAML in {relative_path}: {e}")
def set_yaml_value(build_dir, files_patterns, key_path, value):
"""Sets or replaces a specific key's value in the specified YAML files,
preserving the header.
This function finds all YAML files matching the given patterns and sets a
specified key to a new value. The key can be nested, using dot notation
for the path (e.g., 'parent.child.key').
Unlike `update_yaml_key`, this function will always set the value. If the
key or any part of its path does not exist, it will be created. This is
useful for overwriting existing values or ensuring a key is present with
a specific value.
Args:
build_dir (str): The absolute path to the base directory where the
YAML files are located.
files_patterns (list[str]): A list of file path patterns to process,
relative to `build_dir`. Supports glob patterns.
key_path (str): The dot-separated path to the key to set or create
(e.g., 'collections', 'info.version').
value (any): The new value to assign to the key. This can be any
YAML-compatible type (string, list, dictionary, etc.).
Example:
```yaml
changes:
- type: set_yaml_value
files:
- "special_actions/*/ansible_requirements.yml"
key: "collections"
value: []
```
"""
for file_pattern in files_patterns:
full_pattern = os.path.join(build_dir, file_pattern)
for file_path in glob.glob(full_pattern):
if os.path.exists(file_path):
relative_path = os.path.relpath(file_path, build_dir)
try:
header_lines = read_yaml_header(file_path)
with open(file_path, 'r') as f:
# Skip header lines when loading
for _ in header_lines:
next(f, None)
data = yaml.load(f)
keys = key_path.split('.')
current_level = data
for i, key in enumerate(keys):
if i == len(keys) - 1:
current_level[key] = value
print(f"Set key '{key_path}' in: {relative_path}")
else:
if key not in current_level:
current_level[key] = {}
print(
f"Created missing key '{key}' in path
'{key_path}' in: {relative_path}"
)
current_level = current_level[key]
with open(file_path, 'w') as f:
f.writelines(header_lines)
yaml.dump(data, f)
except Exception as e:
print(f"Error processing YAML in {relative_path}: {e}")
def remove_yaml_list_items(build_dir, files_patterns, list_key_path,
items_to_remove):
"""Removes specific items from a list in the specified YAML files.
This function finds all YAML files matching the given glob patterns and
removes specified items from a list within those files. The list is
identified by a dot-separated key path.
Args:
build_dir (str): The absolute path to the base directory where the
YAML files are located.
files_patterns (list[str]): A list of file path patterns to process,
relative to `build_dir`. Supports glob patterns.
list_key_path (str): The dot-separated path to the list from which
items will be removed (e.g., 'collections').
items_to_remove (list[any]): A list of specification items. Any item
in the target list that matches one of these specifications will
be removed.
Example:
```yaml
changes:
- type: remove_yaml_list_items
files:
- "deploy_scenarios/*/ansible_requirements.yml"
list_key: "collections"
items_to_remove:
- name: "community.sap_install"
```
"""
def item_matches(list_item, spec_item):
"""Check if a list item matches a specification item."""
if isinstance(list_item, dict) and isinstance(spec_item, dict):
# For dicts, check if list_item contains all key-value pairs from
spec_item.
return all(k in list_item and list_item[k] == v for k, v in
spec_item.items())
# For other types (like strings), use simple equality.
return list_item == spec_item
for file_pattern in files_patterns:
full_pattern = os.path.join(build_dir, file_pattern)
for file_path in glob.glob(full_pattern):
if os.path.isfile(file_path):
relative_path = os.path.relpath(file_path, build_dir)
try:
header_lines = read_yaml_header(file_path)
with open(file_path, 'r') as f:
for _ in header_lines:
next(f, None)
data = yaml.load(f)
# Skip if there is nothing to update.
if data is None:
continue
keys = list_key_path.split('.')
current_level = data
modified = False
path_exists = True
for i, key in enumerate(keys):
if not (isinstance(current_level, dict) and key in
current_level):
path_exists = False
break
if i < len(keys) - 1:
current_level = current_level[key]
if not path_exists:
print(f"Warning: Path '{list_key_path}' not found in
{relative_path}. Skipping.")
continue
list_key = keys[-1]
if isinstance(current_level[list_key], list):
target_list = current_level[list_key]
initial_len = len(target_list)
new_list = [item for item in target_list if not
any(item_matches(item, rem_spec) for rem_spec in items_to_remove)]
if len(new_list) < initial_len:
current_level[list_key] = new_list
print(f"Removed {initial_len - len(new_list)}
item(s) from list '{list_key_path}' in: {relative_path}")
modified = True
if modified:
with open(file_path, 'w') as f:
f.writelines(header_lines)
yaml.dump(data, f)
except Exception as e:
print(f"Error processing YAML in {relative_path}: {e}")
def main():
"""Main function to load config and apply changes."""
parser = argparse.ArgumentParser(description="Change files in a specified
directory based on a configuration file.")
parser.add_argument("--build_dir", help="The path to the build directory
where changes will occur." )
parser.add_argument("--config", help="The path to the configuration YAML
file (default: config.yaml)." )
args = parser.parse_args()
config_file = args.config
build_dir = args.build_dir
if not os.path.isdir(build_dir):
print(f"Error: Build directory '{build_dir}' does not exist.")
return
config = load_config(config_file)
changes = config.get('changes', [])
for change in changes:
change_type = change.get('type')
if change_type == 'remove_paths':
remove_paths(build_dir, change.get('paths', []))
elif change_type == 'remove_lines':
remove_lines(build_dir, change.get('files', []),
change.get('patterns', []))
elif change_type == 'replace_text':
replace_text(build_dir, change.get('files', []),
change.get('replacements', []))
elif change_type == 'update_yaml_key':
update_yaml_key(build_dir, change.get('files', []),
change.get('key'), change.get('value'))
elif change_type == 'append_yaml_list':
append_yaml_list(build_dir, change.get('files', []),
change.get('list_key'), change.get('new_item'))
elif change_type == 'set_yaml_value':
set_yaml_value(build_dir, change.get('files', []),
change.get('key'), change.get('value'))
elif change_type == 'remove_yaml_list_items':
remove_yaml_list_items(build_dir, change.get('files', []),
change.get('list_key'), change.get('items_to_remove'))
else:
print(f"Unknown changes type: {change['type']}")
if __name__ == "__main__":
main()