--- /dev/null
+From 7518b647ea0085c231a903c7a3e4351b2b2966c4 Mon Sep 17 00:00:00 2001
+From: Jackie Huang <jackie.huang@windriver.com>
+Date: Wed, 26 Jul 2023 17:23:55 +0800
+Subject: [PATCH 1/4] debrepack: add arm64 support for meta data
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Add set_build_arch (similar to set_build_type) so
+@BUILD_ARCH@ can be used as placeholder in meta data
+files to avoid hardcoded arch names.
+
+The items in dl_path/dl_files in meta_data.yaml may
+have different values and the patches in the patches
+or deb_patches directory may be different for arm64
+arch, this change will allow multiple dl_path/dl_files
+items exist in meta_data.yaml, and multiple series files
+in patches or deb_patches directories exist, and the
+arch specific ones will be used as first priority if
+it exists.
+
+The arch specific ones will have sufix like _arm64,
+e.g. in meta_data.yaml
+
+dl_files:
+ pkg-file-amd64.tar.gz:
+ topdir: pkg-amd64
+ url: https://path/to/pkg-file-amd64.tar.gz
+ sha256sum: <sha256sum value>
+dl_files_arm64:
+ pkg-file-arm64.tar.gz:
+ topdir: pkg-arm64
+ url: https://path/to/pkg-file-arm64.tar.gz
+ sha256sum: <sha256sum value>
+
+dl_path:
+ name: pkg-name-amd64.tar.gz
+ url: https://path/to/pkg-name-amd64.tar.gz
+ sha256sum: <sha256sum value>
+dl_path_arm64:
+ name: pkg-name-arm64.tar.gz
+ url: https://path/to/pkg-name-arm64.tar.gz
+ sha256sum: <sha256sum value>
+
+e.g. for patches/deb_patches
+
+deb_patches
+├── 0001-deb-patch1.patch
+├── 0002-deb-patch2.patch
+├── 0003-arm64-deb-patch1.patch
+├── series
+└── series_arm64
+
+patches
+├── 0001-patch1.patch
+├── 0002-patch2.patch
+├── 0002-arm64-patch1.patch
+├── series
+└── series_arm64
+
+Test Plan:
+PASS: update meta data for packages in repos:
+ - starlingx/integ
+ - starlingx/kernel
+PASS: downloader -s on x86-64 host
+PASS: downloader -s on arm64 host
+PASS: build-pkgs -p <pkg> on x86-64 host
+PASS: build-pkgs -p <pkg> on arm64 host
+PASS: build-pkgs on x86-64 host
+PASS: build-image on x86-64 host
+PASS: build-pkgs on arm64 host
+PASS: build-image on arm64 host
+PASS: Deploy AIO-SX on x86-64 target
+PASS: Deploy AIO-SX on arm64 target
+
+Story: 2010739
+Task: 48013
+
+Change-Id: I42063364c416e40794d85af41e7a22366a84faa1
+Signed-off-by: Jackie Huang <jackie.huang@windriver.com>
+---
+ build-tools/stx/debrepack.py | 114 ++++++++++++++++++++++++++++-------
+ 1 file changed, 93 insertions(+), 21 deletions(-)
+
+diff --git a/build-tools/stx/debrepack.py b/build-tools/stx/debrepack.py
+index 524b38d..85f593b 100755
+--- a/build-tools/stx/debrepack.py
++++ b/build-tools/stx/debrepack.py
+@@ -28,6 +28,7 @@ import sys
+ import utils
+ from utils import run_shell_cmd, get_download_url
+ import yaml
++import platform
+
+
+ RELEASENOTES = " ".join([os.environ.get('PROJECT'), os.environ.get('MY_RELEASE'), "distribution"])
+@@ -58,7 +59,21 @@ if STX_MIRROR_STRATEGY is None:
+ STX_MIRROR_STRATEGY = "stx_mirror_first"
+
+ BTYPE = "@KERNEL_TYPE@"
++BARCH = "@BUILD_ARCH@"
+
++STX_ARCH = "amd64"
++host_arch = platform.machine()
++if host_arch == 'aarch64':
++ STX_ARCH = "arm64"
++
++DL_FILES_DEFAULT = "dl_files"
++DL_FILES_ARCH = DL_FILES_DEFAULT + "_" + STX_ARCH
++
++DL_PATH_DEFAULT = "dl_path"
++DL_PATH_ARCH = DL_PATH_DEFAULT + "_" + STX_ARCH
++
++SERIES_DEFAULT = "series"
++SERIES_ARCH = SERIES_DEFAULT + "_" + STX_ARCH
+
+ class DownloadProgress():
+ def __init__(self):
+@@ -296,6 +311,16 @@ class Parser():
+
+ self.pkginfo["debfolder"] = os.path.join(local_debian)
+
++ def set_build_arch(self):
++
++ local_debian = os.path.join(self.pkginfo["packdir"], "local_debian")
++
++ # clean @BUILD_ARCH@
++ sed_cmd = 'sed -i s#%s#%s#g %s'
++ for root, _, files in os.walk(local_debian):
++ for name in files:
++ run_shell_cmd(sed_cmd % (BARCH, STX_ARCH, os.path.join(root, name)), self.logger)
++
+ def get_gitrevcount_srcdir(self, gitrevcount_obj):
+ src_dir = str(gitrevcount_obj.get("SRC_DIR", ""))
+ if src_dir:
+@@ -463,8 +488,14 @@ class Parser():
+ self.logger.info("Overwrite the debian folder by %s", metadata)
+ run_shell_cmd('cp -r %s/* %s' % (metadata, deb_folder), self.logger)
+
+- series = os.path.join(metadata, "patches/series")
+- if not os.path.isfile(series):
++ series_default = os.path.join(metadata, "patches", SERIES_DEFAULT)
++ series_arch = os.path.join(metadata, "patches", SERIES_ARCH)
++
++ if os.path.isfile(series_arch):
++ series = series_arch
++ elif os.path.isfile(series_default):
++ series = series_default
++ else:
+ return True
+
+ format_ver, format_type = self.set_deb_format()
+@@ -497,11 +528,16 @@ class Parser():
+ run_shell_cmd('cp -rL %s %s' % (src_file, self.pkginfo["srcdir"]),
+ self.logger)
+
+- if "dl_files" in self.meta_data:
++ dl_files = DL_FILES_DEFAULT
++ # Arch specific dl_files have higher priority
++ if DL_FILES_ARCH in self.meta_data:
++ dl_files = DL_FILES_ARCH
++
++ if dl_files in self.meta_data:
+ pwd = os.getcwd()
+ os.chdir(self.pkginfo["packdir"])
+- for dl_file in self.meta_data['dl_files']:
+- dir_name = self.meta_data['dl_files'][dl_file]['topdir']
++ for dl_file in self.meta_data[dl_files]:
++ dir_name = self.meta_data[dl_files][dl_file]['topdir']
+ dl_path = os.path.join(self.pkginfo["packdir"], dl_file)
+ if not os.path.exists(dl_path):
+ self.logger.error("No such file %s in local mirror", dl_file)
+@@ -537,8 +573,15 @@ class Parser():
+ def apply_src_patches(self):
+
+ format_ver, format_type = self.set_deb_format()
+- series = os.path.join(self.pkginfo["debfolder"], "patches/series")
+- if not os.path.isfile(series):
++
++ series_default = os.path.join(self.pkginfo["debfolder"], "patches", SERIES_DEFAULT)
++ series_arch = os.path.join(self.pkginfo["debfolder"], "patches", SERIES_ARCH)
++
++ if os.path.isfile(series_arch):
++ series = series_arch
++ elif os.path.isfile(series_default):
++ series = series_default
++ else:
+ return True
+
+ f = open(series)
+@@ -547,7 +590,13 @@ class Parser():
+ f.close()
+
+ patches_folder = os.path.join(self.pkginfo["srcdir"], "debian/patches")
+- series_file = os.path.join(self.pkginfo["srcdir"], "debian/patches/series")
++ series_file_default = os.path.join(patches_folder, SERIES_DEFAULT)
++ series_file_arch = os.path.join(patches_folder, SERIES_ARCH)
++
++ series_file = series_file_default
++ if os.path.isfile(series_file_arch):
++ series_file = series_file_arch
++
+ if not os.path.isdir(patches_folder):
+ os.mkdir(patches_folder)
+ os.mknod(series_file)
+@@ -587,9 +636,16 @@ class Parser():
+
+ def apply_deb_patches(self):
+
+- series = os.path.join(self.pkginfo["debfolder"], "deb_patches/series")
+- if not os.path.isfile(series):
++ series_default = os.path.join(self.pkginfo["debfolder"], "deb_patches", SERIES_DEFAULT)
++ series_arch = os.path.join(self.pkginfo["debfolder"], "deb_patches", SERIES_ARCH)
++
++ if os.path.isfile(series_arch):
++ series = series_arch
++ elif os.path.isfile(series_default):
++ series = series_default
++ else:
+ return True
++
+ f = open(series)
+ patches = f.readlines()
+ patches_src = os.path.dirname(series)
+@@ -609,8 +665,12 @@ class Parser():
+ return True
+
+ def extract_tarball(self):
++ # Arch specific dl_path have higher priority
++ dl_path = DL_PATH_DEFAULT
++ if DL_PATH_ARCH in self.meta_data:
++ dl_path = DL_PATH_ARCH
+
+- tarball_name = self.meta_data["dl_path"]["name"]
++ tarball_name = self.meta_data[dl_path]["name"]
+ tarball_file = os.path.join(self.pkginfo["packdir"], tarball_name)
+
+ cmd, _, _ = tar_cmd(tarball_name, self.logger)
+@@ -715,9 +775,15 @@ class Parser():
+
+ pwd = os.getcwd()
+ os.chdir(saveto)
+- if "dl_files" in self.meta_data:
+- for dl_file in self.meta_data['dl_files']:
+- dl_file_info = self.meta_data['dl_files'][dl_file]
++
++ dl_files = DL_FILES_DEFAULT
++ # Arch specific dl_files have higher priority
++ if DL_FILES_ARCH in self.meta_data:
++ dl_files = DL_FILES_ARCH
++
++ if dl_files in self.meta_data:
++ for dl_file in self.meta_data[dl_files]:
++ dl_file_info = self.meta_data[dl_files][dl_file]
+ url = dl_file_info['url']
+ if "sha256sum" in dl_file_info:
+ check_cmd = "sha256sum"
+@@ -739,16 +805,21 @@ class Parser():
+ if not checksum(dl_file, check_sum, check_cmd, self.logger):
+ raise Exception(f'Fail to download {dl_file}')
+
+- if "dl_path" in self.meta_data:
+- dl_file = self.meta_data["dl_path"]["name"]
+- url = self.meta_data["dl_path"]["url"]
+- if "sha256sum" in self.meta_data["dl_path"]:
++ dl_path = DL_PATH_DEFAULT
++ # Arch specific dl_path have higher priority
++ if DL_PATH_ARCH in self.meta_data:
++ dl_path = DL_PATH_ARCH
++
++ if dl_path in self.meta_data:
++ dl_file = self.meta_data[dl_path]["name"]
++ url = self.meta_data[dl_path]["url"]
++ if "sha256sum" in self.meta_data[dl_path]:
+ check_cmd = "sha256sum"
+- check_sum = self.meta_data["dl_path"]['sha256sum']
++ check_sum = self.meta_data[dl_path]['sha256sum']
+ else:
+ self.logger.warning(f"{dl_file} missing sha256sum")
+ check_cmd = "md5sum"
+- check_sum = self.meta_data["dl_path"]['md5sum']
++ check_sum = self.meta_data[dl_path]['md5sum']
+ if not checksum(dl_file, check_sum, check_cmd, self.logger):
+ (dl_url, alt_dl_url) = get_download_url(url, self.strategy)
+ if alt_dl_url:
+@@ -813,6 +884,7 @@ class Parser():
+ os.mkdir(self.pkginfo["packdir"])
+
+ self.set_build_type()
++ self.set_build_arch()
+
+ logfile = os.path.join(self.pkginfo["packdir"], self.pkginfo["pkgname"] + ".log")
+ if os.path.exists(logfile):
+@@ -832,7 +904,7 @@ class Parser():
+
+ if "dl_hook" in self.meta_data:
+ self.run_dl_hook()
+- elif "dl_path" in self.meta_data:
++ elif (DL_PATH_DEFAULT or DL_PATH_ARCH) in self.meta_data:
+ self.extract_tarball()
+ elif "src_path" in self.meta_data:
+ self.create_src_package()
+--
+2.30.2
+
--- /dev/null
+From c3a2332443a87b1a5c9477838cae5314413eebe6 Mon Sep 17 00:00:00 2001
+From: Jackie Huang <jackie.huang@windriver.com>
+Date: Wed, 26 Jul 2023 13:06:48 +0800
+Subject: [PATCH 2/4] downloader: add support for arm64
+
+* Check the host arch.
+* Dwnload arch specific binaries for arm64.
+* Support arch specific pkg list files, and the
+ arch specific one (with suffix _arm64) will be used
+ if it exists.
+e.g.
+debian_pkg_dirs
+debian_pkg_dirs_arm64
+debian_pkg_dirs_rt
+debian_pkg_dirs_rt_arm64
+debian_pkg_dirs_installer
+debian_pkg_dirs_installer_arm64
+
+base-bullseye.lst
+base-bullseye_arm64.lst
+
+os-std.lst
+os-std_arm64.lst
+
+Test Plan:
+PASS: update packages list for arm64 in repos:
+ - starlingx/tools
+ - starlingx/kernel
+ - starlingx/integ
+ - starlingx/virt
+ - starlingx/utilities
+PASS: downloader -s -b on x86-64 host
+PASS: downloader -s -b on arm64 host
+PASS: build-pkgs on x86-64 host
+PASS: build-image on x86-64 host
+PASS: build-pkgs on arm64 host
+PASS: build-image on arm64 host
+PASS: Deploy AIO-SX on x86-64 target
+PASS: Deploy AIO-SX on arm64 target
+
+Story: 2010739
+Task: 48013
+
+Change-Id: I5fadf737ee75fc631d57d6bf689d54638548bffe
+Signed-off-by: Jackie Huang <jackie.huang@windriver.com>
+---
+ build-tools/stx/debdownloader | 5 +++++
+ build-tools/stx/downloader | 37 +++++++++++++++++++++++++++--------
+ 2 files changed, 34 insertions(+), 8 deletions(-)
+
+diff --git a/build-tools/stx/debdownloader b/build-tools/stx/debdownloader
+index 6988cc7..a1ca92e 100755
+--- a/build-tools/stx/debdownloader
++++ b/build-tools/stx/debdownloader
+@@ -109,6 +109,7 @@ if __name__ == "__main__":
+ # strip epoch
+ major_ver = version.split(":")[-1]
+ pname_x86 = ''.join([name, '_', major_ver, '_amd64.deb'])
++ pname_arm64 = ''.join([name, '_', major_ver, '_arm64.deb'])
+ pname_all = ''.join([name, '_', major_ver, '_all.deb'])
+ if repomgr.search_pkg(REPO_BIN, name, version):
+ logger.info(''.join([name, '-', version,
+@@ -118,6 +119,10 @@ if __name__ == "__main__":
+ logger.info(''.join([name, '-', version,
+ ' already downloaded, skip download']))
+ debs_need_upload.append(pname_x86)
++ elif debs_downloaded and pname_arm64 in debs_downloaded:
++ logger.info(''.join([name, '-', version,
++ ' already downloaded, skip download']))
++ debs_need_upload.append(pname_arm64)
+ else:
+ if debs_downloaded and pname_all in debs_downloaded:
+ logger.info(''.join([name, '-', version,
+diff --git a/build-tools/stx/downloader b/build-tools/stx/downloader
+index 14d97f7..2d98707 100755
+--- a/build-tools/stx/downloader
++++ b/build-tools/stx/downloader
+@@ -27,8 +27,14 @@ import shutil
+ import signal
+ import sys
+ import utils
++import platform
+
+-DEFAULT_ARCH = 'amd64'
++STX_ARCH = 'amd64'
++host_arch = platform.machine()
++if host_arch == 'aarch64':
++ STX_ARCH = "arm64"
++
++DEB_DISTRO = 'bullseye'
+ REPO_BIN = 'deb-local-binary'
+ mirror_root = os.environ.get('STX_MIRROR')
+ stx_src_mirror = os.path.join(mirror_root, 'sources')
+@@ -115,7 +121,11 @@ def get_all_stx_pkgs():
+ for r in files:
+ # Find all types of package dirs?
+ if r in types_pkg_dirs:
+- pkgs_file = os.path.join(root, r)
++ r_arch = r + "_" + STX_ARCH
++ if os.path.isfile(r_arch):
++ pkgs_file = os.path.join(root, r_arch)
++ else:
++ pkgs_file = os.path.join(root, r)
+ pkgs.update(get_pkgs_from_list(root, pkgs_file))
+ return pkgs
+
+@@ -153,24 +163,34 @@ def get_all_binary_list(distro=STX_DEFAULT_DISTRO, layers=None, build_types=None
+ logger.warning(' '.join([build_type, 'is not a valid build_type for distro', distro, 'of layer', layer]))
+ continue
+
+- pattern=''.join(['os-',build_type,'.lst'])
++ pattern = ''.join(['os-', build_type, '.lst'])
++ pattern_arch = ''.join(['os-', build_type, '_', STX_ARCH, '.lst'])
+ for root, dirs, files in os.walk(search_dir):
+ for f in fnmatch.filter(files, pattern):
+- layer_binaries[layer].append(os.path.join(root, f))
++ f_arch = os.path.join(root, pattern_arch)
++ if os.path.isfile(f_arch):
++ layer_binaries[layer].append(os.path.join(root, f_arch))
++ else:
++ layer_binaries[layer].append(os.path.join(root, f))
+ logger.info(
+ f"Binary lists for layer `{layer}`: "
+ f"{layer_binaries[layer]}"
+ )
+
+ search_dir = os.path.join(stx_config, 'common')
+- pattern='base-*.lst'
++ pattern = ''.join(['base-', DEB_DISTRO, '.lst'])
++ pattern_arch = ''.join(['base-', DEB_DISTRO, '_', STX_ARCH, '.lst'])
+
+ if "common" not in layer_binaries:
+ layer_binaries["common"] = []
+
+ for root, dirs, files in os.walk(search_dir):
+ for f in fnmatch.filter(files, pattern):
+- layer_binaries["common"].append(os.path.join(root, f))
++ f_arch = os.path.join(root, pattern_arch)
++ if os.path.isfile(f_arch):
++ layer_binaries["common"].append(os.path.join(root, f_arch))
++ else:
++ layer_binaries["common"].append(os.path.join(root, f))
+
+ logger.info(
+ f"Binary lists for layer `common`: "
+@@ -727,13 +747,14 @@ if __name__ == "__main__":
+ args.download_source = True
+
+ if args.download_binary:
++
+ all_binary_lists = get_all_binary_list(distro=distro, layers=layers, build_types=build_types)
+- binary_dl = DebDownloader(DEFAULT_ARCH, stx_bin_mirror, clean_mirror, all_binary_lists)
++ binary_dl = DebDownloader(STX_ARCH, stx_bin_mirror, clean_mirror, all_binary_lists)
+ if not binary_dl.create_binary_repo():
+ sys.exit(1)
+
+ if args.download_source:
+- source_dl = SrcDownloader(DEFAULT_ARCH, stx_src_mirror, clean_mirror)
++ source_dl = SrcDownloader(STX_ARCH, stx_src_mirror, clean_mirror)
+
+ dl_register_signal_handler()
+ if binary_dl:
+--
+2.30.2
+
--- /dev/null
+From 516085675edd2a3330b4ddba10c4b613ee91955b Mon Sep 17 00:00:00 2001
+From: Jackie Huang <jackie.huang@windriver.com>
+Date: Wed, 26 Jul 2023 14:55:29 +0800
+Subject: [PATCH 3/4] build-tools: add supoort for arm64
+
+* Check the host arch.
+* use ARCH to replace the hardcoded arch names.
+* Support arch specific pkg list files and yaml files,
+ and the arch specific one (with suffix _arm64) will
+ be used if it exists.
+
+e.g.
+debian-image.inc
+debian-image_arm64.inc
+
+debian_iso_image.inc
+debian_iso_image_arm64.inc
+
+debian_pkg_dirs
+debian_pkg_dirs_arm64
+
+base-bullseye.yaml
+base-bullseye_arm64.yaml
+
+base-initramfs-bullseye.yaml
+base-initramfs-bullseye_arm64.yaml
+
+os-std.lst
+os-std_arm64.lst
+
+Test Plan:
+PASS: update packages list for arm64 in repos:
+ - starlingx/tools
+ - starlingx/kernel
+ - starlingx/integ
+ - starlingx/virt
+ - starlingx/utilities
+PASS: downloader -s -b on x86-64 host
+PASS: downloader -s -b on arm64 host
+PASS: build-pkgs on x86-64 host
+PASS: build-image on x86-64 host
+PASS: build-pkgs on arm64 host
+PASS: build-image on arm64 host
+PASS: Deploy AIO-SX on x86-64 target
+PASS: Deploy AIO-SX on arm64 target
+
+Story: 2010739
+Task: 48013
+
+Change-Id: I9e381f3f04f6747c68d40011c9eda419219c2311
+Signed-off-by: Jackie Huang <jackie.huang@windriver.com>
+---
+ build-tools/stx/aptly_deb_usage.py | 12 ++++--
+ build-tools/stx/build-image | 65 ++++++++++++++++++++++++------
+ build-tools/stx/build-pkgs | 8 +++-
+ build-tools/stx/discovery.py | 42 ++++++++++++++++---
+ build-tools/stx/downloader | 2 +-
+ build-tools/stx/repo_manage.py | 9 ++++-
+ 6 files changed, 111 insertions(+), 27 deletions(-)
+
+diff --git a/build-tools/stx/aptly_deb_usage.py b/build-tools/stx/aptly_deb_usage.py
+index f1d91c2..d10e6a2 100755
+--- a/build-tools/stx/aptly_deb_usage.py
++++ b/build-tools/stx/aptly_deb_usage.py
+@@ -25,6 +25,7 @@ from debian import debian_support
+ import os
+ import time
+ from typing import Optional
++import platform
+
+ PREFIX_LOCAL = 'deb-local-'
+ PREFIX_REMOTE = 'deb-remote-'
+@@ -34,6 +35,11 @@ SIGN_PASSWD = 'starlingx'
+ DEFAULT_TIMEOUT_COUNT = 1
+ STX_DIST = os.environ.get('STX_DIST')
+
++STX_ARCH = 'amd64'
++host_arch = platform.machine()
++if host_arch == 'aarch64':
++ STX_ARCH = "arm64"
++
+ # Class used to manage aptly data base, it can:
+ # create_remote: Create a repository link to a remote mirror
+ # deploy_remote: Sync and deploy a remote mirror
+@@ -326,7 +332,7 @@ class Deb_aptly():
+ self.logger.warning('Drop failed publication %s : %s', publish_name, task_state)
+ return None
+ task = self.aptly.publish.publish(source_kind='local', sources=[{'Name': repo_name}],
+- architectures=['amd64', 'source'], prefix=publish_name,
++ architectures=[STX_ARCH, 'source'], prefix=publish_name,
+ distribution=None, sign_skip=True)
+ task_state = self.__wait_for_task(task, 10)
+ if task_state != 'SUCCEEDED':
+@@ -366,8 +372,8 @@ class Deb_aptly():
+ extra_param['distribution'] = mirror.distribution
+ extra_param['origin'] = None
+ else:
+- # Only support binary_amd64 and source packages
+- extra_param['architectures'] = ['amd64', 'source']
++ # Only support binary_amd64/arm64 and source packages
++ extra_param['architectures'] = [STX_ARCH, 'source']
+ extra_param['distribution'] = None
+ extra_param['origin'] = self.origin
+
+diff --git a/build-tools/stx/build-image b/build-tools/stx/build-image
+index 8536c32..ea04fa2 100755
+--- a/build-tools/stx/build-image
++++ b/build-tools/stx/build-image
+@@ -28,11 +28,17 @@ import sys
+ import time
+ import utils
+ import yaml
++import platform
+
+ STX_DEFAULT_DISTRO = discovery.STX_DEFAULT_DISTRO
+ ALL_LAYERS = discovery.get_all_layers(distro=STX_DEFAULT_DISTRO)
+ ALL_BUILD_TYPES = discovery.get_all_build_types(distro=STX_DEFAULT_DISTRO)
+
++STX_ARCH = 'amd64'
++host_arch = platform.machine()
++if host_arch == 'aarch64':
++ STX_ARCH = "arm64"
++
+ LAT_ROOT = '/localdisk'
+ REPO_ALL = 'deb-merge-all'
+ REPO_BINARY = 'deb-local-binary'
+@@ -48,8 +54,8 @@ IMAGE_LAYERS_PATH = os.path.join(
+ )
+ img_pkgs = []
+ kernel_type = 'std'
+-stx_std_kernel = 'linux-image-5.10.0-6-amd64-unsigned'
+-stx_rt_kernel = 'linux-rt-image-5.10.0-6-rt-amd64-unsigned'
++stx_std_kernel = 'linux-image-5.10.0-6-%s-unsigned' % STX_ARCH
++stx_rt_kernel = 'linux-rt-image-5.10.0-6-rt-%s-unsigned' % STX_ARCH
+ WAIT_TIME_BEFORE_CHECKING_LOG = 2
+ # The max timeout value to wait LAT to output the build log
+ MAX_WAIT_LAT_TIME = 300
+@@ -242,7 +248,7 @@ def update_rt_kernel_in_initramfs_yaml(initramfs_yaml):
+
+ # Updated the name of kernel module
+ for layer in ALL_LAYERS:
+- pkg_dirs = discovery.package_dir_list(distro=STX_DEFAULT_DISTRO, layer=layer, build_type='rt')
++ pkg_dirs = discovery.package_dir_list(distro=STX_DEFAULT_DISTRO, layer=layer, build_type='rt', arch=STX_ARCH)
+ if not pkg_dirs:
+ continue
+ for pkg_dir in pkg_dirs:
+@@ -305,7 +311,7 @@ def add_lat_packages(img_yaml, packages):
+ yaml_doc['packages'].extend(packages)
+
+ for build_type in ALL_BUILD_TYPES:
+- pkgs = discovery.package_iso_list(distro=STX_DEFAULT_DISTRO, layer="all", build_type=build_type)
++ pkgs = discovery.package_iso_list(distro=STX_DEFAULT_DISTRO, layer="all", build_type=build_type, arch=STX_ARCH)
+ yaml_doc['packages'].extend(pkgs)
+
+ yaml_doc['packages'] = list(set(yaml_doc['packages']))
+@@ -319,8 +325,16 @@ def add_lat_packages(img_yaml, packages):
+
+
+ def check_base_os_binaries(repomgr):
+- base_bins_list = os.path.join(os.environ.get('MY_REPO_ROOT_DIR'),
++ base_bins_list_default = os.path.join(os.environ.get('MY_REPO_ROOT_DIR'),
+ 'cgcs-root/build-tools/stx/debian-image.inc')
++ base_bins_list_arch = os.path.join(os.environ.get('MY_REPO_ROOT_DIR'),
++ 'cgcs-root/build-tools/stx',
++ 'debian-image_%s.inc' % STX_ARCH)
++ if os.path.exists(base_bins_list_arch):
++ base_bins_list = base_bins_list_arch
++ else:
++ base_bins_list = base_bins_list_default
++
+ if not os.path.exists(base_bins_list):
+ logger.error(' '.join(['Base OS packages list', base_bins_list,
+ 'does not exist']))
+@@ -338,8 +352,15 @@ def check_base_os_binaries(repomgr):
+
+
+ def check_stx_binaries(repomgr, btype='std'):
+- stx_bins_list = ''.join([PKG_LIST_DIR, '/debian/distro/os-', btype,
+- '.lst'])
++ stx_bins_list_default = ''.join([PKG_LIST_DIR, '/debian/distro/os-',
++ btype, '.lst'])
++ stx_bins_list_arch = ''.join([PKG_LIST_DIR, '/debian/distro/os-',
++ btype, '_', STX_ARCH, '.lst'])
++ if os.path.exists(stx_bins_list_arch):
++ stx_bins_list = stx_bins_list_arch
++ else:
++ stx_bins_list = stx_bins_list_default
++
+ if not os.path.exists(stx_bins_list):
+ logger.warning(' '.join(['STX binary packages list', stx_bins_list,
+ 'does not exist']))
+@@ -660,16 +681,30 @@ if __name__ == "__main__":
+ logger.error("Fail to get prepared to build image")
+ sys.exit(1)
+
+- base_yaml = os.path.join(PKG_LIST_DIR, 'debian/common/base-bullseye.yaml')
+- base_initramfs_yaml = os.path.join(PKG_LIST_DIR, 'debian/common/base-initramfs-bullseye.yaml')
++ base_yaml_default = os.path.join(PKG_LIST_DIR, 'debian/common/base-bullseye.yaml')
++ base_yaml_arch = os.path.join(PKG_LIST_DIR, 'debian/common/base-bullseye_%s.yaml' % STX_ARCH)
++ base_initramfs_yaml_default = os.path.join(PKG_LIST_DIR, 'debian/common/base-initramfs-bullseye.yaml')
++ base_initramfs_yaml_arch = os.path.join(PKG_LIST_DIR, 'debian/common/base-initramfs-bullseye_%s.yaml' % STX_ARCH)
++
+ os.environ["WORKSPACE_DIR"] = LAT_ROOT
+ lat_yaml = os.path.join(LAT_ROOT, "lat.yaml")
+ lat_initramfs_yaml = os.path.join(LAT_ROOT, "lat-initramfs.yaml")
+
+- for yaml_file in (base_yaml, base_initramfs_yaml):
+- if not os.path.exists(yaml_file):
+- logger.error(' '.join(['Base yaml file', yaml_file, 'does not exist']))
+- sys.exit(1)
++ if os.path.exists(base_yaml_arch):
++ base_yaml = base_yaml_arch
++ elif os.path.exists(base_yaml_default):
++ base_yaml = base_yaml_default
++ else:
++ logger.error(' '.join(['Base yaml file', base_yaml_default, 'does not exist']))
++ sys.exit(1)
++
++ if os.path.exists(base_initramfs_yaml_arch):
++ base_initramfs_yaml = base_initramfs_yaml_arch
++ elif os.path.exists(base_initramfs_yaml_default):
++ base_initramfs_yaml = base_initramfs_yaml_default
++ else:
++ logger.error(' '.join(['Base yaml file', base_initramfs_yaml_default, 'does not exist']))
++ sys.exit(1)
+
+ if not os.path.exists(LAT_ROOT):
+ os.makedirs(LAT_ROOT)
+@@ -758,6 +793,10 @@ if __name__ == "__main__":
+ logger.info("build-image successfully done, check the output in %s", LAT_ROOT)
+ ret = 0
+ break
++ if STX_ARCH == "arm64" and "INFO: Create ISO Image: Succeeded" in line:
++ logger.info("build-image successfully done, check the output in %s", LAT_ROOT)
++ ret = 0
++ break
+ # stop latd
+ stop_latd()
+
+diff --git a/build-tools/stx/build-pkgs b/build-tools/stx/build-pkgs
+index a8feaa9..9dacef3 100755
+--- a/build-tools/stx/build-pkgs
++++ b/build-tools/stx/build-pkgs
+@@ -37,7 +37,7 @@ import tempfile
+ import time
+ import utils
+ import yaml
+-
++import platform
+
+ BUILDER_URL = os.environ.get('BUILDER_URL')
+ REPOMGR_URL = os.environ.get('REPOMGR_URL')
+@@ -49,6 +49,10 @@ USER = os.environ.get('MYUNAME')
+ PROJECT = os.environ.get('PROJECT')
+ DISTRIBUTION = os.environ.get('DEBIAN_DISTRIBUTION')
+ STX_ARCH = 'amd64'
++host_arch = platform.machine()
++if host_arch == 'aarch64':
++ STX_ARCH = "arm64"
++
+ STX_META_NAME = 'stx-meta'
+ STX_META_PKG = 'stx-meta_1.0.orig.tar.gz'
+ # Different reasons can lead to package build failure
+@@ -1658,7 +1662,7 @@ class BuildController():
+ logger.error('Failed to specify build_type')
+ return
+
+- pkg_dirs = discovery.package_dir_list(distro=self.attrs['distro'], layer=layer, build_type=build_type)
++ pkg_dirs = discovery.package_dir_list(distro=self.attrs['distro'], layer=layer, build_type=build_type, arch=STX_ARCH)
+ layer_pkg_dirs = pkg_dirs
+ word = "all"
+ if packages:
+diff --git a/build-tools/stx/discovery.py b/build-tools/stx/discovery.py
+index 3de7d48..d16e520 100644
+--- a/build-tools/stx/discovery.py
++++ b/build-tools/stx/discovery.py
+@@ -17,6 +17,7 @@ import os
+ import re
+ import glob
+ import yaml
++import platform
+
+ from git_utils import git_list
+ from repo_utils import repo_root
+@@ -30,6 +31,11 @@ STX_DEFAULT_DISTRO_LIST = [ "debian", "centos" ]
+ STX_DEFAULT_BUILD_TYPE = "std"
+ STX_DEFAULT_BUILD_TYPE_LIST = [STX_DEFAULT_BUILD_TYPE]
+
++STX_ARCH = "amd64"
++STX_SUPPORTED_ARCH = ["amd64", "arm64"]
++host_arch = platform.machine()
++if host_arch == 'aarch64':
++ STX_ARCH = "arm64"
+
+ def get_all_distros():
+ distro_lst = STX_DEFAULT_DISTRO_LIST
+@@ -126,6 +132,14 @@ def get_layer_build_types (layer, distro="debian", skip_non_buildable=True):
+ for proj_dir in project_dir_list_all:
+ for pkg_dir_file in glob.glob("%s/%s%s" % (proj_dir, distro, "_pkg_dirs_*")):
+ bt = os.path.basename(pkg_dir_file).split("_pkg_dirs_")[1]
++ # cleanup arch specific suffix
++ if bt in STX_SUPPORTED_ARCH:
++ continue
++ else:
++ for arch in STX_SUPPORTED_ARCH:
++ arch_suffix = "_" + arch
++ if bt.endswith(arch_suffix):
++ bt = bt.replace(arch_suffix, "")
+ if not bt in bt_lst:
+ bt_lst.append(bt)
+ return sort_build_type_list(bt_lst, layer)
+@@ -137,6 +151,14 @@ def get_all_build_types (distro="debian", skip_non_buildable=True):
+ for proj_dir in project_dir_list_all:
+ for pkg_dir_file in glob.glob("%s/%s%s" % (proj_dir, distro, "_pkg_dirs_*")):
+ bt = os.path.basename(pkg_dir_file).split("_pkg_dirs_")[1]
++ # cleanup arch specific suffix
++ if bt in STX_SUPPORTED_ARCH:
++ continue
++ else:
++ for arch in STX_SUPPORTED_ARCH:
++ arch_suffix = "_" + arch
++ if bt.endswith(arch_suffix):
++ bt = bt.replace(arch_suffix, "")
+ if not bt in bt_lst:
+ bt_lst.append(bt)
+ return sorted(bt_lst)
+@@ -186,32 +208,40 @@ def package_dir_list_handler(entry, proj_dir):
+ return [ path ]
+
+
+-def package_iso_list (distro="debian", layer="all", build_type="std", skip_non_buildable=True):
++def package_iso_list (distro="debian", layer="all", build_type="std", arch=STX_ARCH, skip_non_buildable=True):
+ pkg_iso_list = []
+ if layer is None:
+ layer = "all"
+ for proj_dir in project_dir_list(distro=distro, layer=layer, skip_non_buildable=skip_non_buildable):
+- iso_file = os.path.join(proj_dir, "%s%s%s%s" % (distro, "_iso_image_", build_type, ".inc"))
++ iso_file = os.path.join(proj_dir, "%s_%s_%s_%s%s" % (distro, "iso_image", build_type, arch, ".inc"))
++ if not os.path.isfile(iso_file):
++ iso_file = os.path.join(proj_dir, "%s_%s_%s%s" % (distro, "iso_image", build_type, ".inc"))
+ if not os.path.isfile(iso_file):
+ if build_type == "std":
+ # It's permitted to omit the "_std" suffix from the file name
+- iso_file = os.path.join(proj_dir, "%s%s" % (distro, "_iso_image.inc"))
++ iso_file = os.path.join(proj_dir, "%s_%s_%s%s" % (distro, "iso_image", arch, ".inc"))
++ if not os.path.isfile(iso_file):
++ iso_file = os.path.join(proj_dir, "%s_%s" % (distro, "iso_image.inc"))
+ if not os.path.isfile(iso_file):
+ continue
+ pkg_iso_list.extend(bc_safe_fetch(iso_file))
+ return pkg_iso_list
+
+
+-def package_dir_list (distro="debian", layer="all", build_type="std", skip_non_buildable=True):
++def package_dir_list (distro="debian", layer="all", build_type="std", arch=STX_ARCH, skip_non_buildable=True):
+ pkg_dir_list = []
+ if layer is None:
+ layer = "all"
+ for proj_dir in project_dir_list(distro=distro, layer=layer, skip_non_buildable=skip_non_buildable):
+- pkg_file = os.path.join(proj_dir, "%s%s%s" % (distro, "_pkg_dirs_", build_type))
++ pkg_file = os.path.join(proj_dir, "%s_%s_%s_%s" % (distro, "pkg_dirs", build_type, arch))
++ if not os.path.isfile(pkg_file):
++ pkg_file = os.path.join(proj_dir, "%s_%s_%s" % (distro, "pkg_dirs", build_type))
+ if not os.path.isfile(pkg_file):
+ if build_type == "std":
+ # It's permitted to omit the "_std" suffix from the file name
+- pkg_file = os.path.join(proj_dir, "%s%s" % (distro, "_pkg_dirs"))
++ pkg_file = os.path.join(proj_dir, "%s_%s_%s" % (distro, "pkg_dirs", arch))
++ if not os.path.isfile(pkg_file):
++ pkg_file = os.path.join(proj_dir, "%s_%s" % (distro, "pkg_dirs"))
+ if not os.path.isfile(pkg_file):
+ continue
+ pkg_dir_list.extend(bc_safe_fetch(pkg_file, package_dir_list_handler, proj_dir))
+diff --git a/build-tools/stx/downloader b/build-tools/stx/downloader
+index 2d98707..47093ea 100755
+--- a/build-tools/stx/downloader
++++ b/build-tools/stx/downloader
+@@ -635,7 +635,7 @@ class SrcDownloader(BaseDownloader):
+ logger.warning(' '.join([build_type, 'is not a valid build_type for distro', distro, 'of layer', layer]))
+ continue
+
+- pkg_dirs.extend(discovery.package_dir_list(distro=distro, layer=layer, build_type=build_type))
++ pkg_dirs.extend(discovery.package_dir_list(distro=distro, layer=layer, build_type=build_type, arch=STX_ARCH))
+
+ if not len(pkg_dirs):
+ logger.info("No source packages found")
+diff --git a/build-tools/stx/repo_manage.py b/build-tools/stx/repo_manage.py
+index dbe0cc3..bf68b70 100755
+--- a/build-tools/stx/repo_manage.py
++++ b/build-tools/stx/repo_manage.py
+@@ -31,6 +31,7 @@ import shutil
+ from threading import Lock
+ import urllib.request
+ import utils
++import platform
+
+ REPOMGR_URL = os.environ.get('REPOMGR_URL')
+ REPOMGR_ORIGIN = os.environ.get('REPOMGR_ORIGIN')
+@@ -38,6 +39,10 @@ REPOMGR_DEPLOY_URL = os.environ.get('REPOMGR_DEPLOY_URL')
+
+ APTFETCH_JOBS = 20
+
++STX_ARCH = 'amd64'
++host_arch = platform.machine()
++if host_arch == 'aarch64':
++ STX_ARCH = "arm64"
+
+ class AptFetch():
+ '''
+@@ -497,7 +502,7 @@ class RepoMgr():
+ # kwargs:url: URL of the upstream repo (http://deb.debian.org/debian)
+ # kwargs:distribution: the distribution of the repo (bullseye)
+ # kwargs:component: component of the repo (main)
+- # kwargs:architecture: architecture of the repo, "all" is always enabled. (amd64)
++ # kwargs:architecture: architecture of the repo, "all" is always enabled. (amd64 or arm64)
+ # kwargs:with_sources: include source packages, default is False.
+ # Output: None
+ def mirror(self, repo_name, **kwargs):
+@@ -923,7 +928,7 @@ def subcmd_mirror(subparsers):
+ mirror_parser.add_argument('--component', '-c', help='component name', required=False,
+ default='nginx')
+ mirror_parser.add_argument('--architectures', '-a', help='architectures', required=False,
+- default='amd64')
++ default=STX_ARCH)
+ mirror_parser.add_argument('--with-sources', '-s', help='include source packages',
+ action='store_true')
+ mirror_parser.set_defaults(handle=_handleMirror)
+--
+2.30.2
+
--- /dev/null
+From c0f2e1c04e0a3ceb7a9aff4651186dfb68dc3f16 Mon Sep 17 00:00:00 2001
+From: Jackie Huang <jackie.huang@windriver.com>
+Date: Thu, 27 Jul 2023 23:46:36 +0800
+Subject: [PATCH 4/4] Add debian-image_arm64.inc
+
+syslinux-utils doesn't support arm64, so add
+debian-image_arm64.inc and remove syslinux-utils
+from the list.
+
+diff debian-image.inc debian-image_arm64.inc
+298d297
+< syslinux-utils
+
+Test Plan:
+PASS: downloader -s -b on x86-64 host
+PASS: downloader -s -b on arm64 host
+PASS: build-pkgs on x86-64 host
+PASS: build-image on x86-64 host
+PASS: build-pkgs on arm64 host
+PASS: build-image on arm64 host
+PASS: Deploy AIO-SX on x86-64 target
+PASS: Deploy AIO-SX on arm64 target
+
+Story: 2010739
+Task: 48013
+
+Depends-On: https://review.opendev.org/c/starlingx/root/+/889682
+
+Change-Id: Id655994ee41bd7dfe20399b7acc4a44544d504cb
+Signed-off-by: Jackie Huang <jackie.huang@windriver.com>
+---
+ build-tools/stx/debian-image_arm64.inc | 321 +++++++++++++++++++++++++
+ 1 file changed, 321 insertions(+)
+ create mode 100644 build-tools/stx/debian-image_arm64.inc
+
+diff --git a/build-tools/stx/debian-image_arm64.inc b/build-tools/stx/debian-image_arm64.inc
+new file mode 100644
+index 0000000..432fabb
+--- /dev/null
++++ b/build-tools/stx/debian-image_arm64.inc
+@@ -0,0 +1,321 @@
++acl
++acpi-support-base
++ansible
++apache2
++apparmor-utils
++apt-utils
++auditd
++bash-completion
++bc
++bind9-dnsutils
++bind9-host
++bsdextrautils
++bsdutils
++busybox
++cdebconf
++cloud-init
++cluster-glue
++collectd
++conntrack
++conntrackd
++cracklib-runtime
++cron
++cryptsetup-bin
++curl
++dash
++dbconfig-common
++dbus-user-session
++dconf-gsettings-backend
++debconf-i18n
++diffutils
++dnf
++docker.io
++dosfstools
++e2fsprogs
++efibootmgr
++eject
++elfutils
++erlang-base
++erlang-eldap
++erlang-inets
++erlang-os-mon
++erlang-parsetools
++erlang-syntax-tools
++erlang-tools
++erlang-xmerl
++expect
++fdisk
++findutils
++firmware-ath9k-htc
++firmware-atheros
++firmware-bnx2
++firmware-bnx2x
++firmware-brcm80211
++firmware-cavium
++firmware-intel-sound
++firmware-iwlwifi
++firmware-libertas
++firmware-linux
++firmware-myricom
++firmware-netronome
++firmware-netxen
++firmware-qcom-soc
++firmware-qlogic
++firmware-realtek
++firmware-samsung
++firmware-siano
++flake8
++fonts-dejavu-core
++gcc-10
++genisoimage
++gettext-base
++gnupg
++grep
++gunicorn
++gzip
++hdparm
++hostname
++ifenslave
++init
++initramfs-tools
++inotify-tools
++install-info
++iperf3
++ipmitool
++iptables-persistent
++ipxe-qemu
++iscsiuio
++iotop
++isomd5sum
++kbd
++less
++libapache2-mod-wsgi-py3
++libaprutil1-dbd-sqlite3
++libavahi-glib1
++libbabeltrace1
++libblas3
++libbluetooth3
++libboost-context1.74.0
++libboost-iostreams1.74.0
++libboost-python1.74.0
++libboost-regex1.74.0
++libc6
++libc6-dev
++libcacard0
++libcapstone4
++libcrypt1
++libdebconfclient0
++libdns-export1110
++libeinfo1
++libfam0
++libfuse2
++libgcc-s1
++libgeoip1
++libgfapi0
++libgoogle-perftools4
++libinotifytools0
++libiscsi7
++libjs-jquery-cookie
++liblapack3
++libleveldb1d
++liblognorm5
++libmm-glib0
++libndctl6
++libndp0
++libnetcf1
++libnet-ntp-perl
++libnfs13
++libnm0
++libnss-cache
++libnss-mdns
++libnss-sss
++liboath0
++libodbc1
++libopendbx1
++libpam-sss
++libpciaccess0
++librabbitmq4
++librte-vhost21
++libsanlock-client1
++libsecret-1-0
++libslirp0
++libsoup2.4-1
++libspice-server1
++libssh-4
++libsss-sudo
++libteam-utils
++libunbound8
++liburing1
++libusb-1.0-0
++libusbredirparser1
++libvdeplug2
++libvirglrenderer1
++libyajl2
++linux-cpupower
++locales-all
++logrotate
++lsb-base
++lsof
++man-db
++mawk
++mdadm
++memcached
++mokutil
++multipath-tools
++multipath-tools-boot
++nano
++ncurses-base
++ncurses-bin
++ndisc6
++netcat-openbsd
++nfs-kernel-server
++nftables
++ntp
++ntpdate
++nvme-cli
++open-iscsi
++openssh-server
++original-awk
++ovmf
++pciutils
++pinentry-curses
++pipexec
++postgresql-13
++psmisc
++puppet-module-adrienthebo-filemapper
++puppet-module-asciiduck-sssd
++puppet-module-barbican
++puppet-module-duritong-sysctl
++puppet-module-puppetlabs-mount-core
++puppet-module-voxpupuli-collectd
++puppet-module-vswitch
++pv
++python3-amqplib
++python3-boto3
++python3-castellan
++python3-cherrypy3
++python3-contextlib2
++python3-coverage
++python3-daemon
++python3-dev
++python3-django-debreach
++python3-django-pyscss
++python3-enmerkar
++python3-falcon
++python3-fixtures
++python3-flask-restful
++python3-ipaddr
++python3-keystonemiddleware
++python3-kubernetes
++python3-ldap3
++python3-ldappool
++python3-lz4
++python3-mechanize
++python3-mysqldb
++python3-os-client-config
++python3-oslo.config
++python3-oslo.db
++python3-oslo.log
++python3-oslo.policy
++python3-oslo.rootwrap
++python3-oslo.upgradecheck
++python3-oslo.versionedobjects
++python3-osprofiler
++python3-paramiko
++python3-parted
++python3-passlib
++python3-pastescript
++python3-pecan
++python3-pexpect
++python3-pip
++python3-psutil
++python3-pyelftools
++python3-pyghmi
++python3-pymongo
++python3-pysaml2
++python3-q-text-as-data
++python3-redis
++python3-requests-toolbelt
++python3-retrying
++python3-ruamel.yaml
++python3-scapy
++python3-scrypt
++python3-semantic-version
++python3-sh
++python3-simplejson
++python3-sklearn
++python3-sortedcontainers
++python3-swiftclient
++python3-testtools
++python3-ujson
++python3-warlock
++python3-websockify
++python3-xstatic-angular-bootstrap
++python3-xstatic-angular-fileupload
++python3-xstatic-angular-gettext
++python3-xstatic-angular-lrdragndrop
++python3-xstatic-angular-schema-form
++python3-xstatic-angular-ui-router
++python3-xstatic-bootstrap-datepicker
++python3-xstatic-bootstrap-scss
++python3-xstatic-bootswatch
++python3-xstatic-d3
++python3-xstatic-font-awesome
++python3-xstatic-hogan
++python3-xstatic-jasmine
++python3-xstatic-jquery-migrate
++python3-xstatic-jquery.quicksearch
++python3-xstatic-jquery.tablesorter
++python3-xstatic-jquery-ui
++python3-xstatic-jsencrypt
++python3-xstatic-magic-search
++python3-xstatic-mdi
++python3-xstatic-objectpath
++python3-xstatic-rickshaw
++python3-xstatic-smart-table
++python3-xstatic-spin
++python3-xstatic-term.js
++python-is-python3
++redfishtool
++rng-tools
++rpm
++rsync
++ruby-json
++screen
++seabios
++smartmontools
++socat
++spectre-meltdown-checker
++ssg-debian
++sshpass
++sssd
++sssd-tools
++startpar
++strace
++strongswan
++strongswan-swanctl
++sudo-ldap
++syslog-ng
++sysstat
++sysvinit-utils
++targetcli-fb
++tasksel
++tasksel-data
++tcpdump
++time
++traceroute
++tuned
++tzdata
++udhcpc
++unzip
++uwsgi-plugin-apparmor
++uwsgi-plugin-python3
++vim
++vim-tiny
++vlan
++w3m
++wget
++whiptail
++xclip
++xfsprogs
++zip
+--
+2.30.2
+