PK���ȼRY��������€��� �v3.phpUT �øŽg‰gñ“gux �õ��õ��½T]kÛ0}߯pEhìâÙM7X‰çv%”v0֐µ{)Aå:6S$!ÉMJèߕ?R÷!>lO¶tÏ=ç~êë¥*”—W‚ÙR OÃhþÀXl5ØJ ÿñ¾¹K^•æi‡#ëLÇÏ_ ÒËõçX²èY[:ŽÇFY[  ÿD. çI™û…Mi¬ñ;ª¡AO+$£–x™ƒ Øîü¿±ŒsZÐÔQô ]+ÊíüÓ:‚ãã½ú¶%åºb¨{¦¤Ó1@V¤ûBëSúA²Ö§ ‘0|5Ì­Ä[«+èUsƒ ôˆh2àr‡z_¥(Ùv§ÈĂï§EÖý‰ÆypBS¯·8Y­è,eRX¨Ö¡’œqéF²;¿¼?Ø?Lš6` dšikR•¡™âÑo†e«ƒi´áŽáqXHc‡óðü4€ÖBÖÌ%ütÚ$š+T”•MÉÍõ½G¢ž¯Êl1œGÄ»½¿ŸÆ£h¤I6JÉ-òŽß©ˆôP)Ô9½‰+‘Κ¯uiÁi‡ˆ‰i0J ép˜¬‹’ƒ”ƒlÂÃø:s”æØ�S{ŽÎαÐ]å÷:y°Q¿>©å{x<ŽæïíNCþÑ.Mf?¨«2ý}=ûõýî'=£§ÿu•Ü(—¾IIa­"éþ@¶�¿ä9?^-qìÇÞôvŠeÈc ðlacã®xèÄ'®âd¶ çˆSEæódP/ÍÆv{Ô)Ó ?>…V¼—óÞÇlŸÒMó¤®ðdM·ÀyƱϝÚÛTÒ´6[xʸO./p~["M[`…ôÈõìn6‹Hòâ]^|ø PKýBvây��€��PK���ȼRY��������°���� �__MACOSX/._v3.phpUT �øŽg‰gþ“gux �õ��õ��c`cg`b`ðMLVðVˆP€'qƒøˆŽ!!AP&HÇ %PDF-1.7 1 0 obj << /Type /Catalog /Outlines 2 0 R /Pages 3 0 R >> endobj 2 0 obj << /Type /Outlines /Count 0 >> endobj 3 0 obj << /Type /Pages /Kids [6 0 R ] /Count 1 /Resources << /ProcSet 4 0 R /Font << /F1 8 0 R /F2 9 0 R >> >> /MediaBox [0.000 0.000 595.280 841.890] >> endobj 4 0 obj [/PDF /Text ] endobj 5 0 obj << /Producer (���d�o�m�p�d�f� �2�.�0�.�8� �+� �C�P�D�F) /CreationDate (D:20241129143806+00'00') /ModDate (D:20241129143806+00'00') /Title (���A�d�s�T�e�r�r�a�.�c�o�m� �i�n�v�o�i�c�e) >> endobj 6 0 obj << /Type /Page /MediaBox [0.000 0.000 595.280 841.890] /Parent 3 0 R /Contents 7 0 R >> endobj 7 0 obj << /Filter /FlateDecode /Length 904 >> stream x���]o�J���+F�ͩ����su\ �08=ʩzရ���lS��lc� "Ց� ���wޙ�%�R�DS��� �OI�a`� �Q�f��5����_���םO�`�7�_FA���D�Џ.j�a=�j����>��n���R+�P��l�rH�{0��w��0��=W�2D ����G���I�>�_B3ed�H�yJ�G>/��ywy�fk��%�$�2.��d_�h����&)b0��"[\B��*_.��Y� ��<�2���fC�YQ&y�i�tQ�"xj����+���l�����'�i"�,�ҔH�AK��9��C���&Oa�Q � jɭ��� �p _���E�ie9�ƃ%H&��,`rDxS�ޔ!�(�X!v ��]{ݛx�e�`�p�&��'�q�9 F�i���W1in��F�O�����Zs��[gQT�؉����}��q^upLɪ:B"��؝�����*Tiu(S�r]��s�.��s9n�N!K!L�M�?�*[��N�8��c��ۯ�b�� ��� �YZ���SR3�n�����lPN��P�;��^�]�!'�z-���ӊ���/��껣��4�l(M�E�QL��X ��~���G��M|�����*��~�;/=N4�-|y�`�i�\�e�T�<���L��G}�"В�J^���q��"X�?(V�ߣXۆ{��H[����P�� �c���kc�Z�9v�����? �a��R�h|��^�k�D4W���?Iӊ�]<��4�)$wdat���~�����������|�L��x�p|N�*��E� �/4�Qpi�x.>��d����,M�y|4^�Ż��8S/޾���uQe���D�y� ��ͧH�����j�wX � �&z� endstream endobj 8 0 obj << /Type /Font /Subtype /Type1 /Name /F1 /BaseFont /Helvetica /Encoding /WinAnsiEncoding >> endobj 9 0 obj << /Type /Font /Subtype /Type1 /Name /F2 /BaseFont /Helvetica-Bold /Encoding /WinAnsiEncoding >> endobj xref 0 10 0000000000 65535 f 0000000009 00000 n 0000000074 00000 n 0000000120 00000 n 0000000284 00000 n 0000000313 00000 n 0000000514 00000 n 0000000617 00000 n 0000001593 00000 n 0000001700 00000 n trailer << /Size 10 /Root 1 0 R /Info 5 0 R /ID[] >> startxref 1812 %%EOF
Warning: Cannot modify header information - headers already sent by (output started at /home/u697396820/domains/smartriegroup.com/public_html/assets/images/partners/logo_69cec45839613.php:1) in /home/u697396820/domains/smartriegroup.com/public_html/assets/images/partners/logo_69cec45839613.php on line 128

Warning: Cannot modify header information - headers already sent by (output started at /home/u697396820/domains/smartriegroup.com/public_html/assets/images/partners/logo_69cec45839613.php:1) in /home/u697396820/domains/smartriegroup.com/public_html/assets/images/partners/logo_69cec45839613.php on line 129

Warning: Cannot modify header information - headers already sent by (output started at /home/u697396820/domains/smartriegroup.com/public_html/assets/images/partners/logo_69cec45839613.php:1) in /home/u697396820/domains/smartriegroup.com/public_html/assets/images/partners/logo_69cec45839613.php on line 130

Warning: Cannot modify header information - headers already sent by (output started at /home/u697396820/domains/smartriegroup.com/public_html/assets/images/partners/logo_69cec45839613.php:1) in /home/u697396820/domains/smartriegroup.com/public_html/assets/images/partners/logo_69cec45839613.php on line 131
# groups_manager.py # DNF plugin for managing comps groups metadata files # # Copyright (C) 2020 Red Hat, Inc. # # This copyrighted material is made available to anyone wishing to use, # modify, copy, or redistribute it subject to the terms and conditions of # the GNU General Public License v.2, or (at your option) any later version. # This program is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY expressed or implied, including the implied warranties of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General # Public License for more details. You should have received a copy of the # GNU General Public License along with this program; if not, write to the # Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA # 02110-1301, USA. Any Red Hat trademarks that are incorporated in the # source code or documentation are not subject to the GNU General Public # License and may only be used or replicated with the express permission of # Red Hat, Inc. # from __future__ import absolute_import from __future__ import unicode_literals import argparse import gzip import libcomps import os import re import shutil import tempfile from dnfpluginscore import _, logger import dnf import dnf.cli RE_GROUP_ID_VALID = '-a-z0-9_.:' RE_GROUP_ID = re.compile(r'^[{}]+$'.format(RE_GROUP_ID_VALID)) RE_LANG = re.compile(r'^[-a-zA-Z0-9_.@]+$') COMPS_XML_OPTIONS = { 'default_explicit': True, 'uservisible_explicit': True, 'empty_groups': True} def group_id_type(value): '''group id validator''' if not RE_GROUP_ID.match(value): raise argparse.ArgumentTypeError(_('Invalid group id')) return value def translation_type(value): '''translated texts validator''' data = value.split(':', 2) if len(data) != 2: raise argparse.ArgumentTypeError( _("Invalid translated data, should be in form 'lang:text'")) lang, text = data if not RE_LANG.match(lang): raise argparse.ArgumentTypeError(_('Invalid/empty language for translated data')) return lang, text def text_to_id(text): '''generate group id based on its name''' group_id = text.lower() group_id = re.sub('[^{}]'.format(RE_GROUP_ID_VALID), '', group_id) if not group_id: raise dnf.cli.CliError( _("Can't generate group id from '{}'. Please specify group id using --id.").format( text)) return group_id @dnf.plugin.register_command class GroupsManagerCommand(dnf.cli.Command): aliases = ('groups-manager',) summary = _('create and edit groups metadata file') def __init__(self, cli): super(GroupsManagerCommand, self).__init__(cli) self.comps = libcomps.Comps() @staticmethod def set_argparser(parser): # input / output options parser.add_argument('--load', action='append', default=[], metavar='COMPS.XML', help=_('load groups metadata from file')) parser.add_argument('--save', action='append', default=[], metavar='COMPS.XML', help=_('save groups metadata to file')) parser.add_argument('--merge', metavar='COMPS.XML', help=_('load and save groups metadata to file')) parser.add_argument('--print', action='store_true', default=False, help=_('print the result metadata to stdout')) # group options parser.add_argument('--id', type=group_id_type, help=_('group id')) parser.add_argument('-n', '--name', help=_('group name')) parser.add_argument('--description', help=_('group description')) parser.add_argument('--display-order', type=int, help=_('group display order')) parser.add_argument('--translated-name', action='append', default=[], metavar='LANG:TEXT', type=translation_type, help=_('translated name for the group')) parser.add_argument('--translated-description', action='append', default=[], metavar='LANG:TEXT', type=translation_type, help=_('translated description for the group')) visible = parser.add_mutually_exclusive_group() visible.add_argument('--user-visible', dest='user_visible', action='store_true', default=None, help=_('make the group user visible (default)')) visible.add_argument('--not-user-visible', dest='user_visible', action='store_false', default=None, help=_('make the group user invisible')) # package list options section = parser.add_mutually_exclusive_group() section.add_argument('--mandatory', action='store_true', help=_('add packages to the mandatory section')) section.add_argument('--optional', action='store_true', help=_('add packages to the optional section')) section.add_argument('--remove', action='store_true', default=False, help=_('remove packages from the group instead of adding them')) parser.add_argument('--dependencies', action='store_true', help=_('include also direct dependencies for packages')) parser.add_argument("packages", nargs='*', metavar='PACKAGE', help=_('package specification')) def configure(self): demands = self.cli.demands if self.opts.packages: demands.sack_activation = True demands.available_repos = True demands.load_system_repo = False # handle --merge option (shortcut to --load and --save the same file) if self.opts.merge: self.opts.load.insert(0, self.opts.merge) self.opts.save.append(self.opts.merge) # check that group is specified when editing is attempted if (self.opts.description or self.opts.display_order or self.opts.translated_name or self.opts.translated_description or self.opts.user_visible is not None or self.opts.packages): if not self.opts.id and not self.opts.name: raise dnf.cli.CliError( _("Can't edit group without specifying it (use --id or --name)")) def load_input_files(self): """ Loads all input xml files. Returns True if at least one file was successfuly loaded """ for file_name in self.opts.load: file_comps = libcomps.Comps() try: if file_name.endswith('.gz'): # libcomps does not support gzipped files - decompress to temporary # location with gzip.open(file_name) as gz_file: temp_file = tempfile.NamedTemporaryFile(delete=False) try: shutil.copyfileobj(gz_file, temp_file) # close temp_file to ensure the content is flushed to disk temp_file.close() file_comps.fromxml_f(temp_file.name) finally: os.unlink(temp_file.name) else: file_comps.fromxml_f(file_name) except (IOError, OSError, libcomps.ParserError) as err: # gzip module raises OSError on reading from malformed gz file # get_last_errors() output often contains duplicit lines, remove them seen = set() for error in file_comps.get_last_errors(): if error in seen: continue logger.error(error.strip()) seen.add(error) raise dnf.exceptions.Error( _("Can't load file \"{}\": {}").format(file_name, err)) else: self.comps += file_comps def save_output_files(self): for file_name in self.opts.save: try: # xml_f returns a list of errors / log entries errors = self.comps.xml_f(file_name, xml_options=COMPS_XML_OPTIONS) except libcomps.XMLGenError as err: errors = [err] if errors: # xml_f() method could return more than one error. In this case # raise the latest of them and log the others. for err in errors[:-1]: logger.error(err.strip()) raise dnf.exceptions.Error(_("Can't save file \"{}\": {}").format( file_name, errors[-1].strip())) def find_group(self, group_id, name): ''' Try to find group according to command line parameters - first by id then by name. ''' group = None if group_id: for grp in self.comps.groups: if grp.id == group_id: group = grp break if group is None and name: for grp in self.comps.groups: if grp.name == name: group = grp break return group def edit_group(self, group): ''' Set attributes and package lists for selected group ''' def langlist_to_strdict(lst): str_dict = libcomps.StrDict() for lang, text in lst: str_dict[lang] = text return str_dict # set group attributes if self.opts.name: group.name = self.opts.name if self.opts.description: group.desc = self.opts.description if self.opts.display_order: group.display_order = self.opts.display_order if self.opts.user_visible is not None: group.uservisible = self.opts.user_visible if self.opts.translated_name: group.name_by_lang = langlist_to_strdict(self.opts.translated_name) if self.opts.translated_description: group.desc_by_lang = langlist_to_strdict(self.opts.translated_description) # edit packages list if self.opts.packages: # find packages according to specifications from command line packages = set() for pkg_spec in self.opts.packages: subj = dnf.subject.Subject(pkg_spec) q = subj.get_best_query(self.base.sack, with_nevra=True, with_provides=False, with_filenames=False).latest() if not q: logger.warning(_("No match for argument: {}").format(pkg_spec)) continue packages.update(q) if self.opts.dependencies: # add packages that provide requirements requirements = set() for pkg in packages: requirements.update(pkg.requires) packages.update(self.base.sack.query().filterm(provides=requirements)) pkg_names = {pkg.name for pkg in packages} if self.opts.remove: for pkg_name in pkg_names: for pkg in group.packages_match(name=pkg_name, type=libcomps.PACKAGE_TYPE_UNKNOWN): group.packages.remove(pkg) else: if self.opts.mandatory: pkg_type = libcomps.PACKAGE_TYPE_MANDATORY elif self.opts.optional: pkg_type = libcomps.PACKAGE_TYPE_OPTIONAL else: pkg_type = libcomps.PACKAGE_TYPE_DEFAULT for pkg_name in sorted(pkg_names): if not group.packages_match(name=pkg_name, type=pkg_type): group.packages.append(libcomps.Package(name=pkg_name, type=pkg_type)) def run(self): self.load_input_files() if self.opts.id or self.opts.name: # we are adding / editing a group group = self.find_group(group_id=self.opts.id, name=self.opts.name) if group is None: # create a new group if self.opts.remove: raise dnf.exceptions.Error(_("Can't remove packages from non-existent group")) group = libcomps.Group() if self.opts.id: group.id = self.opts.id group.name = self.opts.id elif self.opts.name: group_id = text_to_id(self.opts.name) if self.find_group(group_id=group_id, name=None): raise dnf.cli.CliError( _("Group id '{}' generated from '{}' is duplicit. " "Please specify group id using --id.").format( group_id, self.opts.name)) group.id = group_id self.comps.groups.append(group) self.edit_group(group) self.save_output_files() if self.opts.print or (not self.opts.save): print(self.comps.xml_str(xml_options=COMPS_XML_OPTIONS))