Merge "patch-builder: support for extra content"
This commit is contained in:
@@ -31,6 +31,13 @@
|
|||||||
</xs:sequence>
|
</xs:sequence>
|
||||||
</xs:complexType>
|
</xs:complexType>
|
||||||
</xs:element>
|
</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:element name="stx_packages">
|
||||||
<xs:complexType>
|
<xs:complexType>
|
||||||
<xs:sequence>
|
<xs:sequence>
|
||||||
|
|||||||
@@ -44,6 +44,7 @@ STX_PACKAGES = 'stx_packages'
|
|||||||
BINARY_PACKAGES = 'binary_packages'
|
BINARY_PACKAGES = 'binary_packages'
|
||||||
SEMANTICS = 'semantics'
|
SEMANTICS = 'semantics'
|
||||||
ACTIVATION_SCRIPTS = 'activation_scripts'
|
ACTIVATION_SCRIPTS = 'activation_scripts'
|
||||||
|
EXTRA_CONTENT = 'extra_content'
|
||||||
|
|
||||||
|
|
||||||
class PatchMetadata(object):
|
class PatchMetadata(object):
|
||||||
@@ -53,6 +54,7 @@ class PatchMetadata(object):
|
|||||||
self.binary_packages = []
|
self.binary_packages = []
|
||||||
self.requires = []
|
self.requires = []
|
||||||
self.activation_scripts = []
|
self.activation_scripts = []
|
||||||
|
self.extra_content = []
|
||||||
|
|
||||||
# Verify if the path to the patch builder folder is set
|
# Verify if the path to the patch builder folder is set
|
||||||
if not PATCH_BUILDER_PATH:
|
if not PATCH_BUILDER_PATH:
|
||||||
@@ -140,6 +142,13 @@ class PatchMetadata(object):
|
|||||||
else:
|
else:
|
||||||
self.__add_text_tag_to_xml(top_tag, ACTIVATION_SCRIPTS, "")
|
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)
|
packages_tag = ET.SubElement(top_tag, PACKAGES)
|
||||||
for package in sorted(self.debs):
|
for package in sorted(self.debs):
|
||||||
self.__add_text_tag_to_xml(packages_tag, "deb", package)
|
self.__add_text_tag_to_xml(packages_tag, "deb", package)
|
||||||
@@ -154,6 +163,9 @@ class PatchMetadata(object):
|
|||||||
return [tag_content]
|
return [tag_content]
|
||||||
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):
|
def _validate_activation_script(self, script_list):
|
||||||
'''
|
'''
|
||||||
Validate if scripts filename start with an integer
|
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)
|
logger.error("Filename '%s' doesn't start with an integer." % fullpath_script)
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
def parse_metadata(self, patch_recipe):
|
def parse_metadata(self, patch_recipe):
|
||||||
self.patch_id = f"{patch_recipe[COMPONENT]}-{patch_recipe[SW_VERSION]}"
|
self.patch_id = f"{patch_recipe[COMPONENT]}-{patch_recipe[SW_VERSION]}"
|
||||||
self.sw_version = patch_recipe[SW_VERSION]
|
self.sw_version = patch_recipe[SW_VERSION]
|
||||||
@@ -192,6 +205,7 @@ class PatchMetadata(object):
|
|||||||
if 'id' in patch_recipe[REQUIRES]:
|
if 'id' in patch_recipe[REQUIRES]:
|
||||||
self.requires = self.__tag_to_list(patch_recipe[REQUIRES]['id'])
|
self.requires = self.__tag_to_list(patch_recipe[REQUIRES]['id'])
|
||||||
self.semantics = patch_recipe[SEMANTICS]
|
self.semantics = patch_recipe[SEMANTICS]
|
||||||
|
|
||||||
if ACTIVATION_SCRIPTS in patch_recipe and 'script' in patch_recipe[ACTIVATION_SCRIPTS]:
|
if ACTIVATION_SCRIPTS in patch_recipe and 'script' in patch_recipe[ACTIVATION_SCRIPTS]:
|
||||||
# the xml parser transform the 'script' value in string or in
|
# the xml parser transform the 'script' value in string or in
|
||||||
# array depending on how much elements we add.
|
# array depending on how much elements we add.
|
||||||
@@ -203,6 +217,20 @@ class PatchMetadata(object):
|
|||||||
scripts_lst.append(self.check_script_path(script))
|
scripts_lst.append(self.check_script_path(script))
|
||||||
self._validate_activation_script(scripts_lst)
|
self._validate_activation_script(scripts_lst)
|
||||||
self.activation_scripts = 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 = []
|
self.debs = []
|
||||||
|
|
||||||
if self.status != 'DEV' and self.status != 'REL':
|
if self.status != 'DEV' and self.status != 'REL':
|
||||||
@@ -210,6 +238,37 @@ class PatchMetadata(object):
|
|||||||
|
|
||||||
logger.debug("Metadata parsed: %s", self)
|
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):
|
def parse_input_xml_data(self):
|
||||||
# Parse and validate the XML
|
# Parse and validate the XML
|
||||||
try:
|
try:
|
||||||
|
|||||||
@@ -95,14 +95,13 @@ class PatchBuilder(object):
|
|||||||
|
|
||||||
|
|
||||||
def build_patch(self):
|
def build_patch(self):
|
||||||
logger.info(f"Generating patch {self.patch_name}")
|
logger.info(f"Patch patch: {self.patch_name}")
|
||||||
|
|
||||||
logger.debug("Fetching debs...")
|
logger.debug("Fetching debs...")
|
||||||
self.fetch_debs.fetch_stx_packages()
|
self.fetch_debs.fetch_stx_packages()
|
||||||
self.fetch_debs.fetch_external_binaries()
|
self.fetch_debs.fetch_external_binaries()
|
||||||
|
|
||||||
logger.info("################ PATCH BUILD ################")
|
logger.info("Building patch...")
|
||||||
logger.info("Download completed, building our patch")
|
|
||||||
|
|
||||||
tmpdir = tempfile.mkdtemp(prefix="patch_")
|
tmpdir = tempfile.mkdtemp(prefix="patch_")
|
||||||
os.chdir(tmpdir)
|
os.chdir(tmpdir)
|
||||||
@@ -128,6 +127,14 @@ class PatchBuilder(object):
|
|||||||
for script in self.metadata.activation_scripts:
|
for script in self.metadata.activation_scripts:
|
||||||
self.copy_rename_script(path_to_script=script, rename=False)
|
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
|
# 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
|
# and upgrade_utils.py from .deb file accessible directly from patch file
|
||||||
if 'software' in self.metadata.stx_packages:
|
if 'software' in self.metadata.stx_packages:
|
||||||
@@ -255,7 +262,8 @@ class PatchBuilder(object):
|
|||||||
"""
|
"""
|
||||||
filelist = ["metadata.tar", "software.tar"]
|
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():
|
for script_id, script_path in self.patch_script_paths.items():
|
||||||
if script_path is not None:
|
if script_path is not None:
|
||||||
|
|||||||
Reference in New Issue
Block a user