Merge "patch-builder: support for extra content"

This commit is contained in:
Zuul
2025-10-09 17:35:33 +00:00
committed by Gerrit Code Review
3 changed files with 78 additions and 4 deletions

View File

@@ -31,6 +31,13 @@
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="extra_content" minOccurs="0">
<xs:complexType>
<xs:sequence>
<xs:element name="item" type="xs:string" maxOccurs="unbounded" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="stx_packages">
<xs:complexType>
<xs:sequence>

View File

@@ -44,6 +44,7 @@ STX_PACKAGES = 'stx_packages'
BINARY_PACKAGES = 'binary_packages'
SEMANTICS = 'semantics'
ACTIVATION_SCRIPTS = 'activation_scripts'
EXTRA_CONTENT = 'extra_content'
class PatchMetadata(object):
@@ -53,6 +54,7 @@ class PatchMetadata(object):
self.binary_packages = []
self.requires = []
self.activation_scripts = []
self.extra_content = []
# Verify if the path to the patch builder folder is set
if not PATCH_BUILDER_PATH:
@@ -140,6 +142,13 @@ class PatchMetadata(object):
else:
self.__add_text_tag_to_xml(top_tag, ACTIVATION_SCRIPTS, "")
if self.extra_content:
extra_content_tag = ET.SubElement(top_tag, EXTRA_CONTENT)
for item in self.extra_content:
self.__add_text_tag_to_xml(extra_content_tag, "item", item.split('/')[-1])
else:
self.__add_text_tag_to_xml(top_tag, EXTRA_CONTENT, "")
packages_tag = ET.SubElement(top_tag, PACKAGES)
for package in sorted(self.debs):
self.__add_text_tag_to_xml(packages_tag, "deb", package)
@@ -154,6 +163,9 @@ class PatchMetadata(object):
return [tag_content]
return tag_content
# TODO: The feature of searching for content in MY_REPO_ROOT_DIR needs to
# be implemented for activation scripts as well.
def _validate_activation_script(self, script_list):
'''
Validate if scripts filename start with an integer
@@ -167,6 +179,7 @@ class PatchMetadata(object):
logger.error("Filename '%s' doesn't start with an integer." % fullpath_script)
sys.exit(1)
def parse_metadata(self, patch_recipe):
self.patch_id = f"{patch_recipe[COMPONENT]}-{patch_recipe[SW_VERSION]}"
self.sw_version = patch_recipe[SW_VERSION]
@@ -192,6 +205,7 @@ class PatchMetadata(object):
if 'id' in patch_recipe[REQUIRES]:
self.requires = self.__tag_to_list(patch_recipe[REQUIRES]['id'])
self.semantics = patch_recipe[SEMANTICS]
if ACTIVATION_SCRIPTS in patch_recipe and 'script' in patch_recipe[ACTIVATION_SCRIPTS]:
# the xml parser transform the 'script' value in string or in
# array depending on how much elements we add.
@@ -203,6 +217,20 @@ class PatchMetadata(object):
scripts_lst.append(self.check_script_path(script))
self._validate_activation_script(scripts_lst)
self.activation_scripts = scripts_lst
if EXTRA_CONTENT in patch_recipe and 'item' in patch_recipe[EXTRA_CONTENT]:
# the xml parser transform the 'script' value in string or in
# array depending on how much elements we add.
if isinstance(patch_recipe[EXTRA_CONTENT]['item'], str):
extra_content_input = [patch_recipe[EXTRA_CONTENT]['item']]
else:
extra_content_input = patch_recipe[EXTRA_CONTENT]['item']
for item in extra_content_input:
candidate_item = self.validate_extra_content(item)
if candidate_item is not None:
self.extra_content.append(candidate_item)
self.debs = []
if self.status != 'DEV' and self.status != 'REL':
@@ -210,6 +238,37 @@ class PatchMetadata(object):
logger.debug("Metadata parsed: %s", self)
# TODO: This funtion is very similar to check_script_path()
# This code can be refactored to use just one of them.
# It's worth refactoring input validation in general.
def validate_extra_content(self, item):
""" Check if item corresponds to existing file/dir
If path is relative, look for content using as parent dir
the current directory, then fallback to MY_REPO_ROOT_DIR
(ie.: /localdisk/designer/USER/PROJECT/)
"""
if not item:
# No input provided
return None
# Cases: Absolute path and path relative to curdir
candidate = os.path.abspath(item)
if os.path.exists(candidate):
return candidate
# Case: Path relative to MY_REPO_ROOT_DIR
parent = utils.get_env_variable('MY_REPO_ROOT_DIR')
candidate = os.path.join(parent, item)
if os.path.exists(candidate):
return candidate
msg = f"Extra content not found: {item}"
logger.error(msg)
raise FileNotFoundError(msg)
def parse_input_xml_data(self):
# Parse and validate the XML
try:

View File

@@ -95,14 +95,13 @@ class PatchBuilder(object):
def build_patch(self):
logger.info(f"Generating patch {self.patch_name}")
logger.info(f"Patch patch: {self.patch_name}")
logger.debug("Fetching debs...")
self.fetch_debs.fetch_stx_packages()
self.fetch_debs.fetch_external_binaries()
logger.info("################ PATCH BUILD ################")
logger.info("Download completed, building our patch")
logger.info("Building patch...")
tmpdir = tempfile.mkdtemp(prefix="patch_")
os.chdir(tmpdir)
@@ -128,6 +127,14 @@ class PatchBuilder(object):
for script in self.metadata.activation_scripts:
self.copy_rename_script(path_to_script=script, rename=False)
# Extra content
if self.metadata.extra_content:
logger.info("Adding in extra content...")
with tarfile.open("extra.tar", "w") as extra_tar:
for item in self.metadata.extra_content:
logger.info(f"Adding: {item}")
extra_tar.add(item, arcname=os.path.join("extra", os.path.basename(item)))
# if the patch includes the 'software' package we need to make deploy-precheck
# and upgrade_utils.py from .deb file accessible directly from patch file
if 'software' in self.metadata.stx_packages:
@@ -255,7 +262,8 @@ class PatchBuilder(object):
"""
filelist = ["metadata.tar", "software.tar"]
### PROCESS EXTRA.TAR HERE
if self.metadata.extra_content:
filelist.append("extra.tar")
for script_id, script_path in self.patch_script_paths.items():
if script_path is not None: