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

Add "get_licenses" feature (reopen #133) #201

Open
wants to merge 12 commits 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
4 changes: 3 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ install:
# develop seems to be required by travis since 02/2013
- if [ $TRAVIS_PYTHON_VERSION == "2.7" -o $TRAVIS_PYTHON_VERSION == "3.4" ]; then pip install pyparsing==2.4.7; fi
- python setup.py build develop
- pip install nose coverage
- pip install nose coverage rosdep
- sudo `which rosdep` init
dirk-thomas marked this conversation as resolved.
Show resolved Hide resolved
- rosdep update
# command to run tests
script:
- nosetests --with-coverage --cover-package=rospkg --with-xunit test
Expand Down
7 changes: 5 additions & 2 deletions src/rospkg/manifest.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
from .common import MANIFEST_FILE, PACKAGE_FILE, STACK_FILE

# stack.xml and manifest.xml have the same internal tags right now
REQUIRED = ['license']
REQUIRED = ['license', 'name']
ALLOWXHTML = ['description']
OPTIONAL = ['author', 'logo', 'url', 'brief', 'description', 'status',
'notes', 'depend', 'rosdep', 'export', 'review',
Expand Down Expand Up @@ -314,7 +314,7 @@ class Manifest(object):
Object representation of a ROS manifest file (``manifest.xml`` and ``stack.xml``)
"""
__slots__ = [
'description', 'brief',
'name', 'description', 'brief',
'author', 'license', 'licenses', 'license_url', 'url',
'depends', 'rosdeps', 'platforms',
'exports', 'version',
Expand All @@ -334,6 +334,7 @@ def __init__(self, type_='package', filename=None, is_catkin=False):
self.version = self.notes = ''
self.licenses = []
self.depends = []
self.licenses = []
self.rosdeps = []
self.exports = []
self.platforms = []
Expand Down Expand Up @@ -396,6 +397,7 @@ def parse_manifest_file(dirpath, manifest_name, rospack=None):
p = parse_package(package_filename)
# put these into manifest
manifest.description = p.description
manifest.name = p.name
manifest.author = ', '.join([('Maintainer: %s' % str(m)) for m in p.maintainers] + [str(a) for a in p.authors])
manifest.license = ', '.join(p.licenses)
manifest.licenses = p.licenses
Expand Down Expand Up @@ -499,6 +501,7 @@ def parse_manifest(manifest_name, string, filename='string'):
pass # manifest is missing optional 'review notes' tag

m.author = _check('author', True)(p, filename)
m.name = _check('name')(p, filename)
m.url = _check('url')(p, filename)
m.version = _check('version')(p, filename)

Expand Down
33 changes: 33 additions & 0 deletions src/rospkg/rospack.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.

from collections import defaultdict, OrderedDict
import os
from threading import Lock

Expand Down Expand Up @@ -327,6 +328,8 @@ class RosPack(ManifestManager):
direct_depends = rp.get_depends('roscpp', implicit=False)
"""

LICENSE_NOT_FOUND= "license_not_found"

def __init__(self, ros_paths=None):
"""
:param ros_paths: Ordered list of paths to search for
Expand Down Expand Up @@ -391,6 +394,36 @@ def stack_of(self, package):
else:
d = os.path.dirname(d)

def get_licenses(self, pkg_name, implicit=True):
"""
@summary: Return a list of licenses and the packages in the dependency tree
for the given package. Special value 'license_not_found' is used as the license for the
packages that license was not detected for.
@param pkg_name: Name of the package the dependency tree begins from.
@return OrderedDict of license name and a list of packages.
@rtype { k, [d] }
@raise ResourceNotFound
"""
license_dict = defaultdict(list)

self.get_depends(name=pkg_name, implicit=implicit)

for p_name, manifest in self._manifests.items():
for license in manifest.licenses:
license_dict[license].append(p_name)

# Traverse for Non-ROS, system packages
pkgnames_rosdep = self.get_rosdeps(package=pkg_name, implicit=implicit)
for pkgname_rosdep in pkgnames_rosdep:
license_dict[self.LICENSE_NOT_FOUND].append(pkgname_rosdep)

# Sort pkg names within the set of pkgs with each license
for list_key in license_dict.values():
list_key.sort()
# Sort licenspe names
licenses = OrderedDict(sorted(license_dict.items()))
return licenses


class RosStack(ManifestManager):
"""
Expand Down
21 changes: 21 additions & 0 deletions test/catkin_package_tests/p1/bar/package.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?xml version="1.0"?>
<package format="2">
<name>bar</name>
<version>1.2.3</version>
<description>
I AM THE VERY MODEL OF A MODERN MAJOR GENERAL
</description>
<maintainer email="someone@example.com">Someone</maintainer>

<license>MIT</license>

<url type="website">http://wiki.ros.org/bar</url>
<url type="bugtracker">http://www.github.com/my_org/bar/issues</url>
<author>Jane Doe</author>
<author email="jane.doe@example.com">Jane Doe</author>

<depend>liburdfdom-dev</depend>
<exec_depend>foo</exec_depend>
<test_depend>gtest</test_depend>
<export />
</package>
3 changes: 0 additions & 3 deletions test/catkin_package_tests/p1/foo/package.xml
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,6 @@
<author>John Doe</author>
<author email="jane.doe@example.com">Jane Doe</author>

<build_depend>catkin</build_depend>
<build_depend version_gte="1.1" version_lt="2.0">genmsg</build_depend>

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why were these dependencies removed in 32e6580?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

According to the commit message, unit test fails as the dependency genmsg doesn't get installed for rospkg itself nor for the unit test. If there's a non-hacky way to install the test dependency I'm happy to add that as well as getting these lines back in.

<build_depend>libboost-thread-dev</build_depend>
<run_depend>libboost-thread</run_depend>

Expand Down
20 changes: 17 additions & 3 deletions test/test_rospkg_catkin_packages.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,17 +40,18 @@


def test_find_packages():
PKGS_EXIST = ['foo', 'bar']
manager = rospkg.rospack.ManifestManager(rospkg.common.MANIFEST_FILE, ros_paths=[search_path])
# for backward compatibility a wet package which is not a metapackage is found when searching for MANIFEST_FILE
assert(len(manager.list()) == 1)
assert(len(manager.list()) == 2)
manager = rospkg.rospack.ManifestManager(rospkg.common.STACK_FILE, ros_paths=[search_path])
assert(len(manager.list()) == 0)
manager = rospkg.rospack.ManifestManager(rospkg.common.PACKAGE_FILE, ros_paths=[search_path])

for pkg_name in manager.list():
assert(pkg_name == 'foo')
assert(pkg_name in PKGS_EXIST)
path = manager.get_path(pkg_name)
assert(path == os.path.join(search_path, 'p1', 'foo'))
assert(path == os.path.join(search_path, 'p1', PKGS_EXIST[PKGS_EXIST.index(pkg_name)]))


def test_get_manifest():
Expand All @@ -67,3 +68,16 @@ def test_licenses():
assert(len(manif.licenses) == 2)
for l in manif.licenses:
assert(l in licenses_list)


def test_get_licenses():
"""Check licenses from all packages in the dependency chain"""
rospack = rospkg.rospack.RosPack(ros_paths=[search_path])
# Union on the licenses of 'bar and 'foo'.
# License for some deps are undetermined so LICENSE_NOT_FOUND.
licenses_list = [rospack.LICENSE_NOT_FOUND, "MIT", "BSD", "LGPL"]
licenses = rospack.get_licenses("bar", implicit=True)
assert("MIT" in licenses)
assert("BSD" in licenses)
assert("LGPL" in licenses)
assert(set(licenses) == set(licenses_list))