[Kimchi-devel] [PATCH 1/3 v3] Adding yumparser module
Aline Manera
alinefm at linux.vnet.ibm.com
Tue Jun 9 14:00:54 UTC 2015
On 05/06/2015 17:17, Daniel Henrique Barboza wrote:
> This module contains:
>
> - functions to write and delete YUM repositories using the .repo files
> from the filesystem directly, without the need of an external API.
>
> - a function to return the software update package list by parsing
> the output of $yum check-update
>
> Signed-off-by: Daniel Henrique Barboza <dhbarboza82 at gmail.com>
> ---
> src/kimchi/yumparser.py | 271 ++++++++++++++++++++++++++++++++++++++++++++++++
> 1 file changed, 271 insertions(+)
> create mode 100644 src/kimchi/yumparser.py
>
> diff --git a/src/kimchi/yumparser.py b/src/kimchi/yumparser.py
> new file mode 100644
> index 0000000..af0396b
> --- /dev/null
> +++ b/src/kimchi/yumparser.py
> @@ -0,0 +1,271 @@
> +#
> +# Project Kimchi
> +#
> +# Copyright IBM, Corp. 2015
> +#
> +# This library is free software; you can redistribute it and/or
> +# modify it under the terms of the GNU Lesser General Public
> +# License as published by the Free Software Foundation; either
> +# version 2.1 of the License, or (at your option) any later version.
> +#
> +# This library is distributed in the hope that it will be useful,
> +# but WITHOUT ANY WARRANTY; without even the implied warranty of
> +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
> +# Lesser General Public License for more details.
> +#
> +# You should have received a copy of the GNU Lesser General Public
> +# License along with this library; if not, write to the Free Software
> +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
> +import subprocess
> +
> +from os import listdir
> +from os.path import isfile, splitext
> +
> +
> +class YumRepoObject(object):
> +
> + def _set_base_URL(self, strvalue):
> + self.baseurl = strvalue
> +
> + def _set_enabled(self, strvalue):
> + self.enabled = (strvalue == '1')
> +
> + def _set_gpgcheck(self, strvalue):
> + self.gpgcheck = (strvalue == '1')
> +
> + def _set_gpgkey(self, strvalue):
> + self.gpgkey = strvalue
> +
> + def _set_metalink(self, strvalue):
> + self.metalink = strvalue
> +
> + def _set_mirrorlist(self, strvalue):
> + self.mirrorlist = strvalue
> +
> + def _set_name(self, strvalue):
> + self.name = strvalue
> +
Those functions are very similar.
I suggest create only 2:
def _set_bool(self, key, strvalue):
setattr(getattr(self, key), strvalue == '1' )
def _set_key(self, key, strvalue):
setattr(getattr(self, key), strvalue)
And use them when needed.
You can also avoid the functions by doing:
def set_atttribute(self, key, value):
if key in ['gpgcheck', 'enabled']:
setattr(getattr(self, key), strvalue == '1' )
else:
setattr(getattr(self, key), strvalue)
> + def __init__(self, repo_id, repofile):
> + self.repo_id = repo_id
> + self.name = None
> + self.baseurl = None
> + self.enabled = True
> + self.gpgcheck = True
> + self.gpgkey = None
> + self.metalink = None
> + self.mirrorlist = None
> + self.repofile = repofile
> + self.attr_setters = {'baseurl': self._set_base_URL,
> + 'enabled': self._set_enabled,
> + 'gpgcheck': self._set_gpgcheck,
> + 'gpgkey': self._set_gpgkey,
> + 'name': self._set_name,
> + 'metalink': self._set_metalink,
> + 'mirrorlist': self._set_mirrorlist}
> +
> + def set_attribute(self, key, value):
> + attr_setter = self.attr_setters.get(key)
> + if attr_setter:
> + return attr_setter(value)
> +
> + def get_attribute_str(self, key):
> + if key not in self.attr_setters.keys():
> + return None
> + if key == 'enabled' or key == 'gpgcheck':
> + str_value = '1' if getattr(self, key) is True else '0'
As 'enabled' and 'gpgcheck' will have a different behavior we can create
a constant to hold the keys:
BOOL_KEYS = ['enabled', 'gpgcheck']
if key in BOOL_KEYS:
do
> + else:
> + str_value = getattr(self, key)
> +
> + if str_value is None:
> + return None
> +
> + return key + '=' + str_value
> +
> + def get_attributes(self):
> + return self.attr_setters.keys()
> +
> + def enable(self):
> + self.enabled = True
> +
> + def disable(self):
> + self.enabled = False
> +
> + def __str__(self):
> + str_obj = '[' + self.repo_id + ']' + '\n'
> + for key in self.get_attributes():
> + if self.get_attribute_str(key) is not None:
> + str_obj += self.get_attribute_str(key) + '\n'
> + return str_obj
> +
> +
> +def get_repo_files():
> + def _is_repository_file(f):
> + _, f_extension = splitext(f)
> + return isfile(f) and (f_extension == '.repo')
> +
> + YUM_REPO_DIR = '/etc/yum.repos.d'
> + return [YUM_REPO_DIR+'/'+f for f in listdir(YUM_REPO_DIR)
> + if _is_repository_file(YUM_REPO_DIR+'/'+f)]
> +
> +
> +def _ignore_line_repo_file(line):
> + return line.startswith("#") or '=' not in line
> +
> +
> +def _get_repos_from_file(repo_file):
> + repos_from_file = {}
> + current_repo = None
> + current_repo_id = None
> + with open(repo_file) as f:
> + for line in f.readlines():
> + line = line.strip()
> + if line.startswith("["):
> + if current_repo is not None:
> + repos_from_file[current_repo_id] = current_repo
> + current_repo_id = line.strip('[]')
> + current_repo = YumRepoObject(current_repo_id, repo_file)
> + continue
> + if _ignore_line_repo_file(line):
> + continue
> + key, value = line.split('=', 1)
> + key = key.strip()
> + value = value.strip()
> + current_repo.set_attribute(key, value)
> +
> + # add the last repo from file
> + repos_from_file[current_repo_id] = current_repo
> +
> + return repos_from_file
> +
> +
> +def get_yum_repositories():
> + repo_files = get_repo_files()
> + repos = {}
> + for yum_repo in repo_files:
> + repos.update(_get_repos_from_file(yum_repo))
> +
> + return repos
> +
> +
> +def _retrieve_repo_line_index(data, repo):
> + repo_entry = '[' + repo.repo_id + ']\n'
> + try:
> + repo_index = data.index(repo_entry)
> + except:
> + return None
> + return repo_index
> +
> +
> +def _update_repo_file_data(data, repo, repo_index):
> + remaining_repo_attrs = repo.get_attributes()
> +
> + for i in range(repo_index + 1, len(data)):
> + line = data[i].strip()
> + if line.startswith('['):
> + break
> + if _ignore_line_repo_file(line):
> + continue
> + key, _ = line.split('=', 1)
> + key = key.strip()
> + attr_str = repo.get_attribute_str(key)
> + if attr_str is None:
> + continue
> + remaining_repo_attrs.remove(key)
> + data[i] = attr_str + '\n'
> +
> + for attr in remaining_repo_attrs:
> + attr_str = repo.get_attribute_str(attr)
> + if attr_str is None:
> + continue
> + data.insert(repo_index+1, attr_str + '\n')
> +
> + return data
> +
> +
> +def write_repo_to_file(repo):
> + with open(repo.repofile) as f:
> + data = f.readlines()
> +
> + repo_index = _retrieve_repo_line_index(data, repo)
> + if repo_index is None:
> + return
> +
> + data = _update_repo_file_data(data, repo, repo_index)
> +
> + with open(repo.repofile, 'w') as f:
> + f.writelines(data)
> +
> +
> +def _get_last_line_repo(data, repo_index):
> + stop_delete_index = None
> + for i in range(repo_index+1, len(data)):
> + line = data[i].strip()
> + if line.startswith('['):
> + stop_delete_index = i - 1
> + break
> + if stop_delete_index is None:
> + stop_delete_index = len(data) - 1
> +
> + return stop_delete_index
> +
> +
> +def _remove_repo_file_data(data, repo_index):
> + last_line_repo = _get_last_line_repo(data, repo_index)
> + for i in range(last_line_repo, repo_index - 1, -1):
> + data.pop(i)
> + return data
> +
> +
> +def delete_repo_from_file(repo):
> + with open(repo.repofile) as f:
> + data = f.readlines()
> +
> + repo_index = _retrieve_repo_line_index(data, repo)
> + if repo_index is None:
> + return
> +
> + data = _remove_repo_file_data(data, repo_index)
> +
> + with open(repo.repofile, 'w') as f:
> + f.writelines(data)
> +
> +
> +class YumUpdatePackageObject(object):
> +
> + def __init__(self, name, arch, version, repo):
> + self.name = name
> + self.arch = arch
> + self.version = version
> + self.ui_from_repo = repo
> +
> +
> +def _get_yum_checkupdate_output():
> + cmd = ['yum', 'check-update', '-d0']
> + yum_update_cmd = subprocess.Popen(cmd,
> + stdout=subprocess.PIPE,
> + stderr=subprocess.PIPE)
> + out, error = yum_update_cmd.communicate()
> + if error != '':
> + return None
> +
> + return out.split()
> +
> +
> +def get_yum_packages_list_update():
> + yum_checkupdate_output = _get_yum_checkupdate_output()
> + if yum_checkupdate_output is None:
> + return None
> +
> + packages = []
> + index = 0
> + while index < len(yum_checkupdate_output):
> + name_arch = yum_checkupdate_output[index]
> + index += 1
> + version = yum_checkupdate_output[index]
> + index += 1
> + repo = yum_checkupdate_output[index]
> + index += 1
> + name, arch = name_arch.rsplit('.', 1)
> + packages.append(YumUpdatePackageObject(name, arch, version, repo))
> +
> + return packages
More information about the Kimchi-devel
mailing list