diff --git a/isocut/isocut.py b/isocut/isocut.py index bd946764558ec17ca30539e82fc6df116e4f48e9..c727c5fa85ffd68d0292fda68eee47e13216c6f1 100644 --- a/isocut/isocut.py +++ b/isocut/isocut.py @@ -12,7 +12,9 @@ PURPOSE. See the Mulan PSL v2 for more details. Author: zhuchunyi Create: 2021-03-17 -Description: Used for iso tailoring at the rpm package level +Description: Used for iso tailoring at the rpm package level. + +Updated by Octopus at 2023-07-26 : add product.xml support """ import argparse @@ -24,6 +26,7 @@ import signal import xml.etree.cElementTree as ET import shlex import traceback +import re # 工具清单 NECESSARY_TOOLS = ( @@ -80,6 +83,8 @@ class IConfig(object): self.cache_path = "/var/run/isocut" self.yum_conf = self.cache_path + "/yum.conf" self.repo_conf = self.cache_path + "/repo.d/isocut.repo" + self.product_xml = None + self.verbose = False self.mkdir_flag = False self.src_iso = None self.dest_iso = None @@ -105,6 +110,8 @@ class IConfig(object): @classmethod def run_cmd(cls, cmd): + if ICONFIG.verbose: + print(cmd) cmd = shlex.split(cmd) res = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) sout = res.communicate() @@ -136,7 +143,6 @@ def parse_old_treeinfo(): #treeinfo文件第3行为version信息 version_line = treeinfo_content[3].strip() ICONFIG.old_version_number = version_line.split('=')[1].strip() - #treeinfo文件第6行为arch信息 version_line = treeinfo_content[6].strip() ICONFIG.src_iso_arch = version_line.split('=')[1].strip() @@ -203,20 +209,24 @@ def check_input(): parser.add_argument("dest_iso", help="destination iso image") parser.add_argument("-temp", metavar="temporary_workspace", default="/tmp", help="temporary path") parser.add_argument("-rpms", metavar="rpm_path", help="extern rpm packages path") + parser.add_argument("-xml", metavar="product_xml", help="provide an anaconda product.xml and disable rpmlist") parser.add_argument("-install_pic", metavar="install_picture_path", help="install bg picture path") parser.add_argument("-kickstart", metavar="kickstart_file_path", help="kickstart file path") parser.add_argument("-product", metavar="product_name", help="product name") parser.add_argument("-version", metavar="version_number", help="version number") + parser.add_argument("-verbose", action='store_true', default=False, help="print all cmdline") args = parser.parse_args() ICONFIG.src_iso = args.source_iso ICONFIG.dest_iso = args.dest_iso ICONFIG.temp_path = args.temp ICONFIG.rpm_path = args.rpms + ICONFIG.product_xml = args.xml ICONFIG.install_pic_path = args.install_pic ICONFIG.ks_file = args.kickstart ICONFIG.input_product_name = args.product ICONFIG.input_version_number = args.version + ICONFIG.verbose = args.verbose if ICONFIG.src_iso is None or ICONFIG.dest_iso is None: print("Must specify source iso image and destination iso image") @@ -227,6 +237,7 @@ def check_input(): return 3 if ICONFIG.rpm_path is not None: + print("RPM path is setted") if not os.path.exists(ICONFIG.rpm_path): print("RPM path do not exist!!") return 3 @@ -364,15 +375,21 @@ def select_rpm(): ret = create_repo_conf() if ret != 0: return 5 - - rpm_list_file = open(ICONFIG.config_rpm_list, "r+") rpm_list = "" - for line in rpm_list_file: - if not (line is None or line.strip() == ""): - rpm_list += " %s" % line[:-1].strip() - cmd = "yumdownloader -y --resolve -c {0} --installroot {1} --destdir {2}/{3} {4}".format( - ICONFIG.yum_conf, ICONFIG.cache_path, ICONFIG.temp_path_new_image, - EXCLUDE_DIR_PACKAGES, rpm_list) + if ICONFIG.product_xml is None: + rpm_list_file = open(ICONFIG.config_rpm_list, "r+") + for line in rpm_list_file: + if not (line is None or line.strip() == ""): + rpm_list += " %s" % line[:-1].strip() + else: + with open(ICONFIG.product_xml, 'r') as file: + xml_content = file.read() + package_names = re.findall(r'(.*?)', xml_content) + rpm_list = ' '.join(package_names) + cmd = "dnf download -y --resolve --alldeps -c {0} --installroot {1} --destdir {2}/{3} \ + --releasever {4} {5}".format( + ICONFIG.yum_conf, ICONFIG.cache_path, ICONFIG.temp_path_new_image, EXCLUDE_DIR_PACKAGES, + ICONFIG.old_version_number, rpm_list) ret = ICONFIG.run_cmd(cmd) if ret[0] != 0 or "conflicting requests" in ret[1]: print("Select rpm failed!!") @@ -401,45 +418,59 @@ def indent(elem, level=0): def regen_repodata(): product_xml = ICONFIG.temp_path_new_image + \ "/" + EXCLUDE_DIR_REPODATA + "/product.xml" - tree = ET.parse(ICONFIG.config_repodata_template) - root = tree.getroot() - packlist = root.find('group/packagelist') - if packlist is None: - print("Can't find packagelist, illegal template!!") - return 6 - with open(ICONFIG.config_rpm_list) as fp_rpm: - for line in fp_rpm: - if line is None or line.strip() == "": - continue - pack = ET.SubElement(packlist, 'packagereq', type='default') - pack.text = line[:-1].strip() - if os.uname()[-1].strip() == 'x86_64': - pack.text = pack.text.split(".x86_64")[0] - elif os.uname()[-1].strip() == 'aarch64': - pack.text = pack.text.split(".aarch64")[0] - elif os.uname()[-1].strip() == 'loongarch64': - pack.text = pack.text.split(".loongarch64")[0] - pack.text = pack.text.split(".noarch")[0] - fp_rpm.close() - - indent(root) - tree.write(product_xml, encoding="UTF-8", xml_declaration=True) - with open(product_xml, 'r+') as f_product: - contents = f_product.readlines() - contents.insert(1, - "\n") - contents_str = "".join(contents) - f_product.seek(0, 0) - f_product.write(contents_str) - f_product.close() - cmd = "createrepo -g {0} {1}".format(product_xml, ICONFIG.temp_path_new_image) - ret = ICONFIG.run_cmd(cmd) - if ret[0] != 0: - print("Regenerate repodata failed!!") - print(ret[1]) - return 6 - + if ICONFIG.product_xml is None: + tree = ET.parse(ICONFIG.config_repodata_template) + root = tree.getroot() + packlist = root.find('group/packagelist') + if packlist is None: + print("Can't find packagelist, illegal template!!") + return 6 + with open(ICONFIG.config_rpm_list) as fp_rpm: + for line in fp_rpm: + if line is None or line.strip() == "": + continue + pack = ET.SubElement(packlist, 'packagereq', type='default') + pack.text = line[:-1].strip() + if os.uname()[-1].strip() == 'x86_64': + pack.text = pack.text.split(".x86_64")[0] + elif os.uname()[-1].strip() == 'aarch64': + pack.text = pack.text.split(".aarch64")[0] + elif os.uname()[-1].strip() == 'loongarch64': + pack.text = pack.text.split(".loongarch64")[0] + pack.text = pack.text.split(".noarch")[0] + fp_rpm.close() + + indent(root) + tree.write(product_xml, encoding="UTF-8", xml_declaration=True) + with open(product_xml, 'r+') as f_product: + contents = f_product.readlines() + contents.insert(1, + "\n") + contents_str = "".join(contents) + f_product.seek(0, 0) + f_product.write(contents_str) + f_product.close() + cmd = "createrepo -g {0} {1}".format(product_xml, ICONFIG.temp_path_new_image) + ret = ICONFIG.run_cmd(cmd) + if ret[0] != 0: + print("Regenerate repodata failed!!") + print(ret[1]) + return 6 + else: + with open(ICONFIG.product_xml, 'r+') as f_product: + contents = f_product.readlines() + contents_str = "".join(contents) + with open(product_xml, 'w+') as tmp_product: + tmp_product.seek(0, 0) + tmp_product.write(contents_str) + tmp_product.close() + cmd = "createrepo -g {0} {1}".format(ICONFIG.product_xml, ICONFIG.temp_path_new_image) + ret = ICONFIG.run_cmd(cmd) + if ret[0] != 0: + print("createrepo_with_product_xml failed!!") + print(ret[1]) + return 6 return 0 # 检查裁剪的ISO所需的rpm包的依赖关系 @@ -626,14 +657,14 @@ def replace_kickstart_file(): return 13 if os.uname()[-1].strip() == 'x86_64': - sed_cmd = r"sed -i '/append/ s/$/ inst.ks=cdrom:\/dev\/cdrom:\/" + KS_NAME + \ + sed_cmd = r"sed -i '/append/ s/$/ inst.ks=hd:LABEL=" + ICONFIG.new_iso_name + ":\/" + KS_NAME + \ " inst.multilib/g' " + ICONFIG.temp_path_new_image + "/" + ISOLINUX_CFG ret = ICONFIG.run_cmd(sed_cmd) if ret[0] != 0: print("Set kickstart file failed!!") return 13 - sed_cmd = r"sed -i '/inst.stage2/ s/$/ inst.ks=cdrom:\/dev\/cdrom:\/" + KS_NAME + \ + sed_cmd = r"sed -i '/inst.stage2/ s/$/ inst.ks=hd:LABEL=" + ICONFIG.new_iso_name + ":\/" + KS_NAME + \ " inst.multilib/g' " + ICONFIG.temp_path_new_image + "/" + EFILINUX_CFG ret = ICONFIG.run_cmd(sed_cmd) if ret[0] != 0: @@ -682,6 +713,8 @@ def add_checksum(): return 0 def add_sha256sum(): + cmd = "chmod 666 {0}".format(ICONFIG.dest_iso) + ret = ICONFIG.run_cmd(cmd) cmd = "sha256sum {0}".format(ICONFIG.dest_iso) ret = ICONFIG.run_cmd(cmd) if ret[0] != 0: @@ -693,6 +726,7 @@ def add_sha256sum(): return 0 def do_clean(): + print('Clean intermediate file...') cmd = "umount {old}".format(old=ICONFIG.temp_path_old_image) ret = ICONFIG.run_cmd(cmd) if ret[0] != 0: diff --git a/isocut/product.xml.example b/isocut/product.xml.example new file mode 100644 index 0000000000000000000000000000000000000000..2ab9e22e6d62c8dcb901125438e9eee9dcc59832 --- /dev/null +++ b/isocut/product.xml.example @@ -0,0 +1,234 @@ + + + + + core + Core + 核心 + Smallest possible installation + 最小安装 + true + false + + audit + kernel + basesystem + bash + coreutils + cronie + curl + dnf + e2fsprogs + filesystem + firewalld + glibc + grubby + hostname + initscripts + iproute + iprutils + iputils + irqbalance + kbd + kexec-tools + less + man-db + ncurses + openssh + openssh-server + openssh-clients + openEuler-release + openEuler-latest-release + parted + passwd + policycoreutils + procps-ng + rng-tools + rootfiles + rpm + selinux-policy-targeted + setup + shadow + sssd + sudo + systemd + tuned + util-linux + vim-minimal + xfsprogs + yum + wget + NetworkManager + NetworkManager-config-server + authselect + dnf-plugins-core + dracut-config-rescue + kernel-tools + sysfsutils + linux-firmware + lshw + lsscsi + rsyslog + security-tool + sg3_utils + dracut-config-generic + dracut-network + rdma-core + selinux-policy-mls + + + + base + Base + 基本 + The standard installation. + true + false + + acl + at + attr + bc + cpio + crontabs + cyrus-sasl + dbus + ed + file + iptstate + irqbalance + kpatch + logrotate + lsof + net-tools + pciutils + psacct + quota + openEuler-release + openEuler-latest-release + sudo + symlinks + systemd-udev + tar + tree + util-linux-user + bash-completion + bpftool + bzip2 + chrony + cockpit + cryptsetup + dos2unix + dosfstools + ethtool + gnupg2 + libstoragemgmt + lvm2 + mailcap + man-pages + mdadm + mlocate + mtr + nano + realmd + rng-tools + rsync + smartmontools + sssd + strace + libteam + time + unzip + usbutils + virt-what + which + words + xfsdump + zip + cifs-utils + cockpit-doc + ima-evm-utils + nfs-utils + traceroute + zsh + + + + ukui + UKUI + UKUI桌面环境 + UKUI desktop environment + UKUI桌面环境 + false + false + + ukui + nodejs-packaging + + + + anaconda-tools + Anaconda tools + Anaconda 工具 + + false + false + + lorax + chrony + cryptsetup + device-mapper-multipath + dosfstools + dracut-network + e2fsprogs + efibootmgr + fcoe-utils + firewalld + gfs2-utils + glibc-all-langpacks + grub2-efi-x64 + grub2-efi-x64-cdboot + grub2-tools + grub2-tools-extra + iscsi-initiator-utils + lvm2 + mdadm + realmd + shim + libteam + tmux + xfsprogs + authselect-compat + kdump-anaconda-addon + + + + product + Product + 产品基础包 + Product base. + 产品基础包。 + 5 + + base + core + + + ukui + + + + + + + + + + + + + + +