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

Fixing cpe data split for cpe fields containing colon #1142

Open
wants to merge 11 commits into
base: master
Choose a base branch
from
39 changes: 39 additions & 0 deletions repology/parsers/cpe.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# Copyright (C) 2019 Dmitry Marakasov <[email protected]>
#
# This file is part of repology
#
# repology is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# repology 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with repology. If not, see <http://www.gnu.org/licenses/>.

from typing import List


def cpe_parse(cpe_str: str) -> List[str]:
escaped = False
current = ''
res = []

for char in cpe_str:
if escaped:
current += '\\' + char
escaped = False
elif char == '\\':
escaped = True
elif char == ':':
res.append(current)
current = ''
else:
current += char

res.append(current)
return res
10 changes: 8 additions & 2 deletions repology/parsers/parsers/gentoo.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
from repology.package import PackageFlags
from repology.packagemaker import NameType, PackageFactory, PackageMaker
from repology.parsers import Parser
from repology.parsers.cpe import cpe_parse
from repology.parsers.maintainers import extract_maintainers
from repology.parsers.versions import VersionStripper
from repology.transformer import PackageTransformer
Expand Down Expand Up @@ -180,8 +181,13 @@ def iter_parse(self, path: str, factory: PackageFactory, transformer: PackageTra
pkg.add_maintainers(xml_metadata.maintainers)

if xml_metadata.cpe is not None:
cpe = xml_metadata.cpe.split(':')
pkg.add_cpe(cpe[2], cpe[3])
cpe = cpe_parse(xml_metadata.cpe)

# distinguish between cpe format 2.2 or 2.3
if cpe[1] == '2.3':
pkg.add_cpe(cpe[3], cpe[4])
else:
pkg.add_cpe(cpe[2], cpe[3])

for ebuild in _iter_ebuilds(path, category, package):
subpkg = pkg.clone(append_ident='/' + ebuild)
Expand Down
44 changes: 44 additions & 0 deletions repology/test/test_cpe.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
#!/usr/bin/env python3
#
# Copyright (C) 2021 Dmitry Marakasov <[email protected]>
#
# This file is part of repology
#
# repology is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# repology 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with repology. If not, see <http://www.gnu.org/licenses/>.

# mypy: no-disallow-untyped-calls

import unittest

from repology.parsers.cpe import cpe_parse


class TestCpe(unittest.TestCase):
def test_cpe_parse(self) -> None:
self.assertEqual(cpe_parse('foo:bar'), ['foo', 'bar'])
self.assertEqual(cpe_parse('foobar'), ['foobar'])
self.assertEqual(cpe_parse('cpe:2.3:a:andreas_mueller:cdrdao'), ['cpe', '2.3', 'a', 'andreas_mueller', 'cdrdao'])
self.assertEqual(cpe_parse('cpe:/a:archive\\:\\:tar_project:archive\\:\\:tar'), ['cpe', '/a', 'archive\\:\\:tar_project', 'archive\\:\\:tar'])
self.assertEqual(cpe_parse('foo\\:bar'), ['foo\\:bar'])
self.assertEqual(cpe_parse('foo\\\\:bar'), ['foo\\\\', 'bar'])

@unittest.expectedFailure
def test_cpe_parse_failure(self) -> None:
self.assertEqual(cpe_parse('a:b'), ['ab'])
self.assertEqual(cpe_parse('foo\\:bar'), ['foo:bar'])
self.assertEqual(cpe_parse('foo\\\\:bar'), ['foo', 'bar'])


if __name__ == '__main__':
unittest.main()