Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

added the opkg/ipkg functionality #51

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion swid_generator/argparser_helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ def meta_for_string(string):
def package_path(string=None):
if not os.path.exists(string):
raise ArgumentTypeError("The file '{0}' does not exist".format(string))
elif string.endswith('.deb') or string.endswith('.rpm') or string.endswith('.pkg.tar.xz'):
elif string.endswith('.deb') or string.endswith('.rpm') or string.endswith('.pkg.tar.xz') or string.endswith('.ipk'):
return string
else:
raise ArgumentTypeError("File '{0}' is not a valid Package.".format(string))
Expand Down
246 changes: 246 additions & 0 deletions swid_generator/environments/opkg_environment.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,246 @@
# -*- coding: utf-8 -*-
from __future__ import print_function, division, absolute_import, unicode_literals

import subprocess
import ntpath

from swid_generator.generators.utils import create_temp_folder
from swid_generator.command_manager import CommandManager as CM
from .common import CommonEnvironment
from ..package_info import PackageInfo, FileInfo


class OpkgEnvironment(CommonEnvironment):
"""
Environment class for distributions using opkg as package manager (e.g.
Wind River Linux).

The packages are retrieved from the database using the ``opkg info`` tool.
"""
executable_query = 'opkg'
executable = 'opkg'
md5_hash_length = 32
conffile_file_name = './conffiles'
control_archive = 'control.tar.gz'

installed_states = {
'install ok installed': True,
'deinstall ok config-files': False
}

required_packages_for_package_file_method = [
"tar",
"ar"
]

required_packages_for_sign_method = [
"xmlsec1"
]

@classmethod
def get_package_list(cls, ctx=None):
"""
Get list of installed packages.

Returns:
List of ``PackageInfo`` instances.

"""
result = []
command_args = [cls.executable_query, 'info']

command_output = CM.run_command_check_output(command_args)

line_list = command_output.split('\t')

for line in line_list:
split_line = line.split('\n')

if len(split_line) >= 5:
package_info = PackageInfo()
package_info.package = split_line[0]
package_info.version = split_line[1]
package_info.status = split_line[2]
package_info.summary = split_line[3]

result.append(package_info)

return [r for r in result if cls._package_installed(r)]

@classmethod
def get_files_for_package(cls, package_info):
"""
Get list of files related to the specified package.

Args:
package_info (PackageInfo):
The ``PackageInfo`` instance for the query.

Returns:
List of ``FileInfo`` instances.

"""

result = []
stripped_lines = []

command_args_normal_files = [cls.executable_query, '-L', package_info.package]
command_normal_file_output = CM.run_command_check_output(command_args_normal_files)

lines = command_normal_file_output.rstrip().split('\n')
normal_files = filter(cls._is_file, lines)

command_args_config_files = [cls.executable_query, '-W', '-f=${conffiles}\\n', package_info.package]
command_config_file_output = CM.run_command_check_output(command_args_config_files)

lines = command_config_file_output.split('\n')

for line in lines:
if len(line) != 0:
path_without_md5 = line.strip()[:len(line.strip()) - cls.md5_hash_length].strip()
stripped_lines.append(path_without_md5)

config_files = filter(cls._is_file, stripped_lines)

for config_file_path in config_files:
file_info = FileInfo(config_file_path)
file_info.mutable = True
result.append(file_info)

for file_path in normal_files:
if file_path not in config_files:
result.append(FileInfo(file_path))

return sorted(result, key=lambda f: f.full_pathname)

@classmethod
def _package_installed(cls, package_info):
"""
Try to find out whether the specified package is installed or not.

If the installed state cannot be determined with certainty we assume
it's installed.

Args:
package_info (package_info.PackageInfo):
The package to check.

Returns:
True or False

"""
return cls.installed_states.get(package_info.status, True)

@classmethod
def get_files_from_packagefile(cls, file_pathname):
"""
Extract all information of a .deb package.
- List of all files
- List of all Configuration-files

This Method extract all the information in a temporary directory. The Debian package
is extracted to the temporary directory, this because the files are needed to compute the File-Hash.

:param file_pathname: Path to the .deb package
:return: Lexicographical sorted List of FileInfo()-Objects (Conffiles and normal Files)
"""
save_options = create_temp_folder(file_pathname)

result = []
result_help_list = [] # needed to check duplications

command_args_unpack_package = [cls.executable, '-x', save_options['absolute_package_path'], save_options['save_location']]
command_args_extract_controlpackage = ["ar", "x", save_options['absolute_package_path'], cls.control_archive]
command_args_extract_conffile = ["tar", "-zxf", "/".join((save_options['save_location'], cls.control_archive)), cls.conffile_file_name]
command_args_file_list = [cls.executable, '-c', file_pathname]

def _add_to_result_list(file_path, actual_path, mutable=False):
result_help_list.append(file_path)
file_info = FileInfo(file_path, actual_path=False)
file_info.set_actual_path(actual_path)
file_info.mutable = mutable
result.append(file_info)

# Extraction of all needed Files (Store Files into tmp folder), extract Configuration-Files entries
try:
CM.run_command(command_args_unpack_package)
CM.run_command(command_args_extract_controlpackage, working_directory=save_options['save_location'])
CM.run_command(command_args_extract_conffile, working_directory=save_options['save_location'])

temp_conffile_save_location = "/".join((save_options['save_location'], cls.conffile_file_name))

with open(temp_conffile_save_location, 'rb') as afile:
file_content = afile.read().encode('utf-8')

except(IOError, subprocess.CalledProcessError):
# If no file extracted from command -> no .conffile-File exists
file_content = None
config_file_paths = []

# Extract Configuration-Files-Entries from output
if file_content is not None:
config_file_paths = filter(lambda path: len(path) > 0, file_content.split('\n'))

for config_file_path in config_file_paths:
_add_to_result_list(config_file_path, save_options['save_location'] + config_file_path, mutable=True)

# Extraction of file-list
output_file_list = CM.run_command_check_output(command_args_file_list)
line_list = output_file_list.split('\n')

for line in line_list:

splitted_line = line.split(' ')
directory_or_file_path = splitted_line[-1]

if "->" in splitted_line:
# symbol-link
symbol_link = (splitted_line[-3])[1:]
temp_save_location_symbol_link = "/".join((save_options['save_location'], symbol_link))
head, _ = ntpath.split(symbol_link)

if "../" in directory_or_file_path:
root, _ = ntpath.split(head)
directory_or_file_path = root + directory_or_file_path[2:]
else:
directory_or_file_path = "/".join((head, directory_or_file_path))

if cls._is_file(temp_save_location_symbol_link):
if symbol_link not in config_file_paths and symbol_link not in result_help_list:
_add_to_result_list(symbol_link, temp_save_location_symbol_link)
else:
directory_or_file_path = directory_or_file_path[1:]

temp_save_location_file = "/".join((save_options['save_location'], directory_or_file_path))

if cls._is_file(temp_save_location_file):
if directory_or_file_path not in config_file_paths and directory_or_file_path not in result_help_list:
_add_to_result_list(directory_or_file_path, temp_save_location_file)

return sorted(result, key=lambda f: f.full_pathname)

@classmethod
def get_packageinfo_from_packagefile(cls, file_path, ctx=None):
"""
Extract the Package-Name and the Package-Version from the Debian-Package.

:param file_path: Path to the Debian-Package
:param ctx: ctx, needed for opkg_include_package_arch
:return: A PackageInfo()-Object with Package-Version and Package-Name.
"""
command_args_packagename = [cls.executable, 'info', file_path, '--fields', 'Package']
command_args_version = [cls.executable, 'info', file_path, '--fields', 'Version']
command_args_arch = [cls.executable, 'info', file_path, '--fields', 'Architecture']
package_name = CM.run_command_check_output(command_args_packagename)
package_version = CM.run_command_check_output(command_args_version)

package_info = PackageInfo()
package_info.package = package_name.strip()

if ctx and ctx['dpkg_include_package_arch']:
package_arch = CM.run_command_check_output(command_args_arch)
package_info.version = package_version.strip() + '.' + package_arch.strip()
else:
package_info.version = package_version.strip()

return package_info
3 changes: 3 additions & 0 deletions swid_generator/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@

from glob import glob
from shutil import rmtree

from swid_generator.environments.opkg_environment import OpkgEnvironment
from .argparser import MainArgumentParser
from .environments.environment_registry import EnvironmentRegistry
from .environments.dpkg_environment import DpkgEnvironment
Expand All @@ -50,6 +52,7 @@ def main():
environment_registry.register('rpm', RpmEnvironment)
environment_registry.register('dpkg', DpkgEnvironment)
environment_registry.register('pacman', PacmanEnvironment)
environment_registry.register('opkg', OpkgEnvironment)

# Parse arguments
parser = MainArgumentParser(environment_registry)
Expand Down