def rpm2cati(file_path: str) -> str: """ Converts rpm package to cati package and returns generated cati package file path Args: file_path: rpm package filepath Returns: returns generated cati package filepath """ # require alien if os.system('alien 2> /dev/null') != 256: return file_path file_path = os.path.abspath(file_path) cwd = os.getcwd() tmp_dir = Temp.make_dir() os.chdir(tmp_dir) try: shutil.copy(file_path, 'package.rpm') res = os.system('alien package.rpm 2> /dev/null') if res != 0: return file_path os.system('mv *.deb package.deb') rpm_path = file_path + '.deb' try: shutil.copy('package.deb', rpm_path) except: rpm_path = Temp.make_file() shutil.copy('package.deb', rpm_path) os.chdir(cwd) return deb2cati(rpm_path) except: os.chdir(cwd) return file_path
def install(self, pkg: BaseArchive, index_updater_events: dict, installer_events: dict, is_manual=True, run_scripts=True, target_path='', keep_conffiles=False, check_security_blacklist=True): """ Install .cati package Args: pkg (BaseArchive): the package archive object index_updater_events (dict): events will be passed to `dotcati.ListUpdater.update_indexes()` installer_events (dict): The events - package_currently_install: gets the current installed version - package_new_installs: gets package archive - package_installed: will call after package installation - dep_and_conflict_error: will run when there is depends or conflict error - arch_error: will run when package arch is not sync with sys arch is_manual (bool): installed package as manual or not (default is True means manual) run_scripts (bool): run package install scripts or not (default is True) target_path (str): where is the target path for installed files (will pass to `self.copy_files()`) keep_conffiles (bool): stil keep config files if changed (default is True) check_security_blacklist (bool): check package is in security blacklist or not """ self.conffiles = pkg.get_conffiles() self.pkg = pkg self.keep_conffiles = keep_conffiles self.uncopied_conffiles = {} # check package is in security blacklist if check_security_blacklist: self.check_security_blacklist(pkg) # check package architecture if not pkg.data['arch'] in SysArch.allowed_archs(): return installer_events['arch_error'](pkg) # check package dependencies and conflicts try: self.check_dep_and_conf(pkg) except DependencyError as ex: return installer_events['dep_and_conflict_error'](pkg, ex) except ConflictError as ex: return installer_events['dep_and_conflict_error'](pkg, ex) # load old conffiles self.old_conffiles = [] try: f = open(Env.installed_lists('/' + pkg.data['name'] + '/conffiles'), 'r') content = f.read() f.close() tmp = content.strip().split('\n') self.old_conffiles = [item.strip().split('@') for item in tmp] except: pass # add package data to lists if not os.path.isdir(Env.packages_lists('/' + pkg.data['name'])): os.mkdir(Env.packages_lists('/' + pkg.data['name'])) lists_path = Env.packages_lists('/' + pkg.data['name'] + '/' + pkg.data['version'] + '-' + pkg.data['arch']) try: lists_f = open(lists_path, 'r') old_repo = json.loads(lists_f.read())['repo'] lists_f.close() except: old_repo = 'Local' try: lists_f = open(lists_path, 'r') old_file_path = json.loads(lists_f.read())['file_path'] lists_f.close() except: old_file_path = False try: lists_f = open(lists_path, 'r') old_file_sha256 = json.loads(lists_f.read())['file_sha256'] lists_f.close() except: old_file_sha256 = False try: lists_f = open(lists_path, 'r') old_file_md5 = json.loads(lists_f.read())['file_md5'] lists_f.close() except: old_file_md5 = False lists_f = open(lists_path, 'w') pkg.data['repo'] = old_repo if old_file_path != False: pkg.data['file_path'] = old_file_path tmp_pkg_data = pkg.data if old_file_md5: tmp_pkg_data['file_md5'] = old_file_md5 if old_file_sha256: tmp_pkg_data['file_sha256'] = old_file_sha256 tmp_pkg_data['files'] = ['/' + member[6:] for member in pkg.members() if member[:6] == 'files/'] lists_f.write(json.dumps(tmp_pkg_data)) lists_f.close() ListUpdater.update_indexes(index_updater_events) # extract package in a temp place temp_dir = Temp.make_dir() os.rmdir(temp_dir) try: pkg.extractall(temp_dir) except IsADirectoryError: pass self.extracted_package_dir = temp_dir # install package if Pkg.is_installed(pkg.data['name']): installer_events['package_currently_installed'](pkg, Pkg.installed_version(pkg.data['name'])) else: installer_events['package_new_installs'](pkg) if run_scripts: self.run_script('ins-before') copied_files = self.copy_files(pkg, installer_events['directory_not_empty'], target_path) # set install configuration if not os.path.isdir(Env.installed_lists('/' + pkg.data['name'])): os.mkdir(Env.installed_lists('/' + pkg.data['name'])) f_ver = open(Env.installed_lists('/' + pkg.data['name'] + '/ver'), 'w') f_ver.write(pkg.data['version']) # write installed version f_ver.close() # write copied files list f_files = open(Env.installed_lists('/' + pkg.data['name'] + '/files'), 'w') copied_files_str = '' for copied_file in copied_files: copied_files_str += copied_file + '\n' f_files.write(copied_files_str.strip()) # write copied files f_files.close() # write conffiles list f_conffiles = open(Env.installed_lists('/' + pkg.data['name'] + '/conffiles'), 'w') copied_conffiles_str = '' for copied_conffile in copied_files: if copied_conffile.split(':')[0] == 'cf': try: conffile_hash = self.uncopied_conffiles[copied_conffile.split(':', 1)[-1]] except: conffile_hash = calc_file_sha256(Env.base_path(copied_conffile.split(':', 1)[-1])) copied_conffiles_str += conffile_hash + '@' + copied_conffile.split(':', 1)[-1] + '\n' f_conffiles.write(copied_conffiles_str.strip()) # write copied conffiles f_conffiles.close() # copy `any` script if os.path.isfile(self.extracted_package_dir + '/scripts/any'): os.system('cp "' + self.extracted_package_dir + '/scripts/any' + '" "' + Env.any_scripts('/' + pkg.data['name']) + '"') # save static files list static_files_list = pkg.get_static_files() f_static_files = open(Env.installed_lists('/' + pkg.data['name'] + '/staticfiles'), 'w') static_files_str = '' for copied_file in copied_files: copied_file_path = copied_file.split(':', 1)[1] if copied_file_path in static_files_list: if os.path.isfile(Env.base_path('/' + copied_file_path)): # calculate file sha256 sum copied_file_sha256 = calc_file_sha256(Env.base_path('/' + copied_file_path)) # add file to list static_files_str += copied_file_sha256 + '@' + copied_file_path + '\n' f_static_files.write(static_files_str.strip()) # write copied files f_static_files.close() f_installed_at = open(Env.installed_lists('/' + pkg.data['name'] + '/installed_at'), 'w') f_installed_at.write(str(time.time())) # write time (installed at) f_installed_at.close() if is_manual: f_manual = open(Env.installed_lists('/' + pkg.data['name'] + '/manual'), 'w') f_manual.write('') f_manual.close() if run_scripts: self.run_script('ins-after') # copy remove scripts if os.path.isfile(self.extracted_package_dir + '/scripts/rm-before'): os.system( 'cp "' + self.extracted_package_dir + '/scripts/rm-before' + '" "' + Env.installed_lists('/' + pkg.data['name'] + '/rm-before') + '"' ) if os.path.isfile(self.extracted_package_dir + '/scripts/rm-after'): os.system( 'cp "' + self.extracted_package_dir + '/scripts/rm-after' + '" "' + Env.installed_lists('/' + pkg.data['name'] + '/rm-after') + '"' ) # pop package from state BaseTransaction.pop_state() # call package installed event installer_events['package_installed'](pkg)
def deb2cati(file_path: str) -> str: """ Converts deb package to cati package and returns generated cati package file path Args: file_path: deb package filepath Returns: returns generated cati package filepath """ file_path = os.path.abspath(file_path) tmp_dir = Temp.make_dir() cwd = os.getcwd() os.chdir(tmp_dir) try: shutil.copy(file_path, './package.deb') script = ''' ar -x package.deb mkdir cati mkdir cati/control cati/scripts mv control.tar.* cati/control mkdir cati/files mv data.tar.* cati/files rm debian-binary package.deb touch cati/data.json '''.strip().split('\n') script = [l.strip() for l in script] for line in script: result = os.system(line) if result != 0: # script has error, return current filepath os.chdir(cwd) return file_path os.chdir('cati/control') os.system('tar -xf control.tar.*') os.system('rm control.tar.*') os.chdir('..') os.chdir('files') os.system('tar -xf data.tar.*') os.system('rm data.tar.*') os.chdir('..') # convert content data to cati json control_f = open('control/control', 'r').read() control_f_lines = control_f.strip().split('\n') control_fields = {} tmp_last_key = None for line in control_f_lines: if line != '': if line[0] == ' ': if tmp_last_key != None: control_fields[tmp_last_key] += '\n' + line else: key = line.split(':', 1)[0] value = line.split(':', 1)[1].strip() tmp_last_key = key control_fields[key] = value # convert scripts if os.path.isfile('control/preinst'): shutil.copy('control/preinst', 'scripts/ins-before') if os.path.isfile('control/postinst'): shutil.copy('control/postinst', 'scripts/ins-after') if os.path.isfile('control/prerm'): shutil.copy('control/prerm', 'scripts/rm-before') if os.path.isfile('control/postrm'): shutil.copy('control/postrm', 'scripts/rm-after') # convert control fields to cati data.json cati_data = {} for k in control_fields: if k == 'Package': cati_data['name'] = control_fields[k].strip() elif k == 'Version': cati_data['version'] = control_fields[k].strip() elif k == 'Architecture': cati_data['arch'] = control_fields[k].strip() elif k == 'Maintainer': cati_data['maintainer'] = control_fields[k].strip() elif k == 'Original-Maintainer': cati_data['X-Original-Maintainer'] = control_fields[k].strip() elif k == 'Uploaders': cati_data['uploaders'] = control_fields[k].strip().split(',') cati_data['uploaders'] = [a.strip() for a in cati_data['uploaders']] elif k == 'Description': cati_data['description'] = control_fields[k] elif k == 'Changed-By': cati_data['changed-by'] = control_fields[k] elif k == 'Changes': cati_data['changes'] = control_fields[k] elif k == 'Date': cati_data['date'] = control_fields[k] elif k == 'Urgency': cati_data['urgency'] = control_fields[k] elif k == 'Essential': cati_data['essential'] = control_fields[k] if cati_data['essential'] == 'yes' or cati_data['essential'] == 'Yes': cati_data['essential'] = True else: cati_data['essential'] = False elif k == 'Homepage': cati_data['homepage'] = control_fields[k].strip() elif k == 'Section': cati_data['category'] = [control_fields[k].strip()] elif k == 'Depends' or k == 'Pre-Depends': try: cati_data['depends'] except: cati_data['depends'] = [] cati_data['depends'] = [*cati_data['depends'], *convert_depends_list(control_fields[k].strip())] elif k == 'Conflicts' or k == 'Breaks': try: cati_data['conflicts'] except: cati_data['conflicts'] = [] cati_data['conflicts'] = [*cati_data['conflicts'], *convert_depends_list(control_fields[k].strip())] elif k == 'Recommends': cati_data['recommends'] = convert_depends_list(control_fields[k].strip()) elif k == 'Replaces': cati_data['replaces'] = convert_depends_list(control_fields[k].strip()) elif k == 'Suggests': cati_data['suggests'] = convert_depends_list(control_fields[k].strip()) cati_data['suggests'] = [item_tmp.split(' ')[0] for item_tmp in cati_data['suggests']] elif k == 'Enhances': cati_data['enhances'] = convert_depends_list(control_fields[k].strip()) cati_data['enhances'] = [item_tmp.split(' ')[0] for item_tmp in cati_data['enhances']] elif k == 'Provides': cati_data['provides'] = convert_depends_list(control_fields[k].strip()) cati_data['provides'] = [item_tmp.split(' ')[0] for item_tmp in cati_data['provides']] elif k[0] == 'X' or k[0] == 'x': cati_data[k] = control_fields[k].strip() os.system('rm control -rf') cati_data_f = open('data.json', 'w') cati_data_f.write(json.dumps(cati_data)) cati_data_f.close() os.chdir('..') # build pkg pkg_command = PkgCommand.PkgCommand() pkg_command.handle(ArgParser.parse(['cati', 'pkg', 'build', 'cati', '-q'])) if os.path.isfile('cati.cati'): try: shutil.copy('cati.cati', file_path + '.cati') os.chdir(cwd) return file_path + '.cati' except: tmp_file_path = Temp.make_file() shutil.copy('cati.cati', tmp_file_path) return tmp_file_path except Exception as ex: print('error: ' + str(ex)) os.chdir(cwd) return file_path os.chdir(cwd) return file_path