Skip to content

Commit

Permalink
add check for circular dependencies
Browse files Browse the repository at this point in the history
  • Loading branch information
anxdpanic committed Feb 18, 2019
1 parent 7002802 commit 602122f
Show file tree
Hide file tree
Showing 7 changed files with 153 additions and 4 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ It can also be used locally for detecting problems in your addons.

- Check if all PO files are valid

- Check for circular dependencies

All of the validation and checks are done according to the kodi [addon rules](https://kodi.wiki/view/Add-on_rules)

## Installation
Expand Down
14 changes: 10 additions & 4 deletions kodi_addon_checker/addons/Repository.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,19 @@


class Repository(object):
def __init__(self, version, path):
def __init__(self, version, path, local_xml=False):
super(Repository, self).__init__()
self.version = version
self.path = path
gz_file = requests.get(path, timeout=(10, 10)).content
with gzip.open(BytesIO(gz_file), 'rb') as xml_file:
content = xml_file.read()

if local_xml:
with open(path, 'rb') as xml_file:
content = xml_file.read()
else:
gz_file = requests.get(path, timeout=(10, 10)).content
with gzip.open(BytesIO(gz_file), 'rb') as xml_file:
content = xml_file.read()

tree = ET.fromstring(content)
self.addons = []
for addon in tree.findall("addon"):
Expand Down
2 changes: 2 additions & 0 deletions kodi_addon_checker/check_addon.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@ def start(addon_path, args, all_repo_addons, config=None):

check_dependencies.check_reverse_dependencies(addon_report, addon_id, args.branch, all_repo_addons)

check_dependencies.check_circular_dependencies(addon_report, all_repo_addons, parsed_xml, args.branch)

check_files.check_file_permission(addon_report, file_index)

check_files.check_for_invalid_xml_files(addon_report, file_index)
Expand Down
52 changes: 52 additions & 0 deletions kodi_addon_checker/check_dependencies.py
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,58 @@ def check_reverse_dependencies(report: Report, addon: str, branch_name: str, all
.format(", ".join(sorted([r.id for r in rdependsLowerBranch])), len(rdependsLowerBranch))))


def check_circular_dependencies(report: Report, all_repo_addons: dict, parsed_xml, branch_name: str):
"""Check for any circular dependencies in addon.xml file and reports them
:all_repo_addons: dictionary return by all_repo_addon() function
:parsed_xml: parsed addon.xml file
:branch_name: name of the kodi branch/version
"""
root_addon = Addon(parsed_xml)
ignore_list = _get_ignore_list(branch_name)

dependencies = []
dependency_tree = {}

# add dependencies of `addon` to dependencies list
def add_dependencies(addon):
new_depends = []
for dependency in addon.dependencies:
# don't check ignored for dependencies
if dependency.id in ignore_list:
continue
new_depends.append(dependency)

if addon.id not in dependency_tree:
dependency_tree[addon.id] = []
if new_depends:
dependency_tree[addon.id] = [d.id for d in new_depends]
dependencies.extend(new_depends)

add_dependencies(root_addon)

i = 0
# add all dependencies and their dependencies
while i < len(dependencies):
if dependencies[i].id not in dependency_tree:
for branch, repo in sorted(all_repo_addons.items()):
found_addon = repo.find(dependencies[i].id)
if found_addon:
add_dependencies(found_addon)
i += 1

if dependency_tree:
circular_dependencies = []
dependencies = list(dependency_tree.keys())

for depend in dependencies:
if root_addon.id in dependency_tree.get(depend, []):
circular_dependencies.append(depend)

if circular_dependencies:
report.add(Record(PROBLEM, "Circular dependencies: {}"
.format(", ".join(sorted(set(circular_dependencies))))))


def _get_ignore_list(branch_name):

if branch_name == "leia":
Expand Down
39 changes: 39 additions & 0 deletions tests/test_check_dependencies.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import unittest

from os.path import abspath, dirname, join
import xml.etree.ElementTree as ET

from kodi_addon_checker.addons.Repository import Repository
from kodi_addon_checker.check_dependencies import check_circular_dependencies
from kodi_addon_checker.common import load_plugins
from kodi_addon_checker.record import Record
from kodi_addon_checker.reporter import ReportManager
from kodi_addon_checker.report import Report


HERE = abspath(dirname(__file__))


class TestCheckDependencies(unittest.TestCase):

def setUp(self):
load_plugins()
ReportManager.enable(["array"])
self.report = Report("")
self.branch = 'krypton'

def test_check_circular_dependency(self):
self.path = join(HERE, 'test_data', 'Circular_depend')
addon_xml = join(self.path, "addon.xml")
addons_xml = join(self.path, "addons.xml")

parsed_xml = ET.parse(addon_xml).getroot()
all_repo_addons = {self.branch: Repository(self.branch, addons_xml, local_xml=True)}

check_circular_dependencies(self.report, all_repo_addons, parsed_xml, self.branch)

records = [Record.__str__(r) for r in ReportManager.getEnabledReporters()[0].reports]
self.output = [record for record in records if record.startswith("ERROR: Circular")]
self.expected = ["ERROR: Circular dependencies: plugin.test.one"]

self.assertListEqual(self.expected, self.output)
23 changes: 23 additions & 0 deletions tests/test_data/Circular_depend/addon.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?xml version='1.0' encoding='utf-8'?>
<addon id="plugin.test.two" version="0.0.1" name="Testing" provider-name="Tester">
<requires>
<import addon="xbmc.python" version="2.25.0"/>
<import addon="plugin.test.one"/>
</requires>
<extension point="xbmc.python.pluginsource" library="addon.py">
<provides>video</provides>
</extension>
<extension point="xbmc.addon.metadata">
<summary lang="en_GB">Testing</summary>
<description lang="en_GB">Testing</description>
<language>en</language>
<disclaimer>This is just a test</disclaimer>
<platform>all</platform>
<license>GPL-3.0-only</license>
<assets>
<icon>icon.png</icon>
<fanart>fanart.jpg</fanart>
</assets>
<news>Testing 123</news>
</extension>
</addon>
25 changes: 25 additions & 0 deletions tests/test_data/Circular_depend/addons.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?xml version='1.0' encoding='utf-8'?>
<addons>
<addon id="plugin.test.one" version="0.0.1" name="Testing" provider-name="Tester">
<requires>
<import addon="xbmc.python" version="2.25.0"/>
<import addon="plugin.test.two"/>
</requires>
<extension point="xbmc.python.pluginsource" library="addon.py">
<provides>video</provides>
</extension>
<extension point="xbmc.addon.metadata">
<summary lang="en_GB">Testing</summary>
<description lang="en_GB">Testing</description>
<language>en</language>
<disclaimer>This is just a test</disclaimer>
<platform>all</platform>
<license>GPL-3.0-only</license>
<assets>
<icon>icon.png</icon>
<fanart>fanart.jpg</fanart>
</assets>
<news>Testing 123</news>
</extension>
</addon>
</addons>

0 comments on commit 602122f

Please sign in to comment.