pax_global_header00006660000000000000000000000064135735216170014524gustar00rootroot0000000000000052 comment=a7f1673f5391c86a2fddf123017e86a250752aab rosdistro-0.8.0/000077500000000000000000000000001357352161700135615ustar00rootroot00000000000000rosdistro-0.8.0/.gitignore000066400000000000000000000000641357352161700155510ustar00rootroot00000000000000_build build deb_dist dist *.pyc rosdistro.egg-info rosdistro-0.8.0/.travis.yml000066400000000000000000000010361357352161700156720ustar00rootroot00000000000000language: python sudo: false python: - "2.7" - "3.4" - "3.5" - "3.6" # command to install dependencies install: # develop seems to be required by travis since 02/2013 - python setup.py build develop # newer versions of docutils dropped support for Python 3.4 - if [ $TRAVIS_PYTHON_VERSION == "3.4" ]; then pip install docutils==0.15.2; fi - pip install PyYAML argparse catkin_pkg rospkg setuptools - pip install nose coverage mock # command to run tests script: - nosetests --with-xunit test notifications: email: false rosdistro-0.8.0/LICENSE.txt000066400000000000000000000030001357352161700153750ustar00rootroot00000000000000Software License Agreement (BSD License) Copyright (c) 2012, Willow Garage, Inc. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of Willow Garage, Inc. nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.rosdistro-0.8.0/Makefile000066400000000000000000000010641357352161700152220ustar00rootroot00000000000000.PHONY: all setup clean_dist distro clean install NAME=rosdistro VERSION=`./setup.py --version` UNAME := $(shell uname) all: echo "noop for debbuild" setup: echo "building version ${VERSION}" clean_dist: -rm -f MANIFEST -rm -rf dist -rm -rf deb_dist distro: setup clean_dist python setup.py sdist clean: clean_dist echo "clean" install: distro sudo checkinstall python setup.py install testsetup: echo "running rosdistro! tests" test: testsetup python setup.py nosetests test--pdb-failures: testsetup python setup.py nosetests --pdb-failures rosdistro-0.8.0/README.md000066400000000000000000000001021357352161700150310ustar00rootroot00000000000000rosdistro ========= Tools to work with catkinized rosdistro filesrosdistro-0.8.0/README.rst000066400000000000000000000007331357352161700152530ustar00rootroot00000000000000rosdistro ===== Code & tickets -------------- +----------------------+-----------------------------------------------------------+ | rosdistro | http://github.com/ros-infrastructure/rosdistro | +----------------------+-----------------------------------------------------------+ | Issues | http://github.com/ros-infrastructure/rosdistro/issues | +----------------------+-----------------------------------------------------------+ rosdistro-0.8.0/doc/000077500000000000000000000000001357352161700143265ustar00rootroot00000000000000rosdistro-0.8.0/doc/Makefile000066400000000000000000000005001357352161700157610ustar00rootroot00000000000000.PHONY: html apidoc clean upload SPHINXAPIDOC=sphinx-apidoc html: apidoc $(MAKE) -C _build html apidoc: $(SPHINXAPIDOC) -F -o _build ../src/rosdistro sed -i "s/_build/./g" _build/Makefile clean: -rm -rf _build upload: html scp -r _build/html/ rosbot@ros.osuosl.org:/home/rosbot/docs/independent/api/rosdistro/ rosdistro-0.8.0/scripts/000077500000000000000000000000001357352161700152505ustar00rootroot00000000000000rosdistro-0.8.0/scripts/rosdistro000077500000000000000000000041661357352161700172350ustar00rootroot00000000000000#!/usr/bin/env python import optparse import sys import rosdistro def depends(args): distro = rosdistro.RosDistro(args[1]) deps = distro.get_depends(args[2:], int(args[0])) for t, dep in deps.iteritems(): print('%s depends:' % t) print(', '.join(dep)) def depends_on(args): distro = rosdistro.RosDistro(args[1]) deps = distro.get_depends_on(args[2:], int(args[0])) for t, dep in deps.iteritems(): print('%s depends_on:' % t) print(', '.join(dep)) def help(cmd=None): print("Usage: %s [command]" % sys.argv[0]) print(" With [command] one of the following") if cmd and type(cmd) == list: cmd = cmd[0] if cmd and cmd not in cmds: print("Unknown command %s" % cmd) cmd = None if cmd and cmd == 'help': cmd = None for c, ops in cmds.iteritems(): res = " '%s'" % c res += (' ' * (30 - len(res))) res += "with arguments: '%s'" % (' '.join(ops['args'])) if not cmd or cmd == c: print(res) cmds = {'help': {'args': ['command'], 'cmd': help}, 'depends': {'args': ['depth', 'ros_version', 'package_list'], 'cmd': depends}, 'depends_on': {'args': ['depth', 'ros_version', 'package_list'], 'cmd': depends_on}} def main(): parser = optparse.OptionParser() parser.add_option("--cache", action="store", default=None) (options, commands) = parser.parse_args() # usage if len(commands) == 0: help() return # command specific usage cmd = commands[0] if cmd in cmds: args = cmds[cmd]['args'] if len(commands) - 1 < len(args): help(cmd) return else: help(cmd) return # execute command try: cmds[cmd]['cmd'](commands[1:]) except Exception as e: print(e) print("Failure") return distro = rosdistro.RosDistro(args(0), options.cache) for r in distro.get_repositories(): print("Caching %s" % r) distro.get_depends1(r) print("Cache written to %s" % (distro.depends_file.local_url)) if __name__ == "__main__": main() rosdistro-0.8.0/scripts/rosdistro_build_cache000077500000000000000000000101631357352161700215310ustar00rootroot00000000000000#!/usr/bin/env python # Software License Agreement (BSD License) # # Copyright (c) 2013, Open Source Robotics Foundation, Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # * Redistributions in binary form must reproduce the above # copyright notice, this list of conditions and the following # disclaimer in the documentation and/or other materials provided # with the distribution. # * Neither the name of Open Source Robotics Foundation, Inc. nor # the names of its contributors may be used to endorse or promote # products derived from this software without specific prior # written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. from __future__ import print_function import argparse import gzip import logging import sys from rosdistro import logger from rosdistro.distribution_cache_generator import CacheYamlDumper, generate_distribution_caches import yaml logging.basicConfig(level=logging.INFO) def parse_args(args=sys.argv[1:]): parser = argparse.ArgumentParser( description='Build the cache for rosdistro distributions.' ) add = parser.add_argument add( 'index', help='The path or url of the index.yaml file (must be either a local file or a file:// url)') add( 'dist_names', nargs='*', help='The names of the distributions (default: all)') add( '--debug', action='store_true', default=False, help='Output debug messages') add( '--preclean', action='store_true', default=False, help='Build the cache from scratch instead of reusing cached data') add( '--ignore-local', action='store_true', default=False, help='Ignore locally available cache') add( '--include-source', action='store_true', default=False, help='Also include source branch package XMLs in the cache') return parser.parse_args(args) def main(): args = parse_args() if args.debug: logger.level = logging.DEBUG try: caches = generate_distribution_caches( args.index, dist_names=args.dist_names, preclean=args.preclean, ignore_local=args.ignore_local, include_source=args.include_source, debug=args.debug) except RuntimeError as e: print(str(e), file=sys.stderr) sys.exit(1) for dist_name, cache in caches.items(): if args.dist_names and dist_name not in args.dist_names: continue # write the cache data = yaml.dump(cache.get_data(), Dumper=CacheYamlDumper) with open('%s-cache.yaml' % dist_name, 'w') as f: print('- write cache file "%s-cache.yaml"' % dist_name) f.write(data) with gzip.open('%s-cache.yaml.gz' % dist_name, 'wb') as f: # On Python 3, we must encode the unicode yaml str prior to gzipping it, # whereas for Python 2, the yaml output is a str which cannot be further # encoded (compared with a unicode object). if sys.version_info[0] >= 3: data = data.encode('utf-8') print('- write compressed cache file "%s-cache.yaml.gz"' % dist_name) f.write(data) if __name__ == '__main__': main() rosdistro-0.8.0/scripts/rosdistro_convert000077500000000000000000000246501357352161700207750ustar00rootroot00000000000000#!/usr/bin/env python # Software License Agreement (BSD License) # # Copyright (c) 2013, Open Source Robotics Foundation, Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # * Redistributions in binary form must reproduce the above # copyright notice, this list of conditions and the following # disclaimer in the documentation and/or other materials provided # with the distribution. # * Neither the name of Open Source Robotics Foundation, Inc. nor # the names of its contributors may be used to endorse or promote # products derived from this software without specific prior # written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. from __future__ import print_function import os import shutil import subprocess import sys import tempfile try: from urllib.error import HTTPError except ImportError: from urllib2 import HTTPError from rosdistro.loader import load_url from rosdistro.release_file import ReleaseFile import yaml BASE_SRC_URL = 'https://raw.github.com/ros/rosdistro/master' def get_targets(): url = BASE_SRC_URL + '/releases/targets.yaml' print('Load "%s"' % url) yaml_str = load_url(url) data = yaml.load(yaml_str) targets = {} for d in data: targets[d.keys()[0]] = d.values()[0] return targets def convert_release(dist_name, targets): url = BASE_SRC_URL + '/releases/%s.yaml' % dist_name print('Load "%s"' % url) yaml_str = load_url(url) input_ = yaml.load(yaml_str) # improve conversion performance by reusing results from last run last_dist = None if os.path.exists(dist_name + '/release.yaml'): with open(dist_name + '/release.yaml', 'r') as f: last_data = yaml.load(f.read()) last_dist = ReleaseFile(dist_name, last_data) output = {} output['type'] = 'release' output['version'] = 1 output['platforms'] = {'ubuntu': targets[dist_name]} output['repositories'] = {} for repo_name in sorted(input_['repositories']): input_repo = input_['repositories'][repo_name] output_repo = {} output_repo['url'] = input_repo['url'] output_repo['version'] = input_repo['version'] if output_repo['version'] is None: print('- "' + repo_name + '" has no version') del output_repo['version'] pkg_name = repo_name if 'packages' in input_repo: output_repo['packages'] = {} unary_repo = len(input_repo['packages']) == 1 for pkg_name in input_repo['packages']: if unary_repo: if input_repo['packages'][pkg_name] is None: if pkg_name == repo_name: del output_repo['packages'] else: output_repo['packages'][pkg_name] = {'subfolder': pkg_name} else: output_repo['packages'][pkg_name] = input_repo['packages'][pkg_name] break output_repo['packages'][pkg_name] = None if input_repo['packages'][pkg_name] is not None and input_repo['packages'][pkg_name] != pkg_name: output_repo['packages'][pkg_name] = {'subfolder': input_repo['packages'][pkg_name]} output['repositories'][repo_name] = output_repo if 'version' in output_repo and output_repo['version'] is not None: tag_template = _get_tag_template(dist_name, output_repo, pkg_name, last_dist.repositories[repo_name] if last_dist and repo_name in last_dist.repositories else None) output_repo['tags'] = {'release': tag_template} yaml_str = yaml.dump(output, default_flow_style=False) yaml_str = yaml_str.replace(': null', ':') with open(dist_name + '/release.yaml', 'w') as f: f.write('%YAML 1.1\n') f.write('# ROS release file\n') f.write('# see REP 137: http://ros.org/reps/rep-0137.html\n') f.write('---\n') f.write(yaml_str) def _get_tag_template(dist_name, repo, pkg_name, last_repo=None): # reuse tag template if fetched before for the same repo and version if last_repo and last_repo.version == repo['version']: if 'release' in last_repo.tags: return last_repo.tags['release'] assert 'github.com' in repo['url'] release_tag = 'release/{0}/{1}/{2}'.format(dist_name, pkg_name, repo['version']) url = _github_raw_url(repo['url'], release_tag) print('- ' + pkg_name + ': ' + url) try: try: load_url(url) return 'release/%s/{package}/{version}' % dist_name except HTTPError: # try alternative tag upstream_version = repo['version'].split('-')[0] release_tag = 'release/{0}/{1}'.format(pkg_name, upstream_version) url = _github_raw_url(repo['url'], release_tag) print('- ' + pkg_name + ': ' + url) load_url(url) return 'release/{package}/{upstream_version}' except HTTPError as e: raise RuntimeError('Could not determine tag using %s, %s, %s: %s' % (dist_name, repo, pkg_name, e)) def _github_raw_url(url, tag): url = url.replace('.git', '/tree/%s/' % tag) url = url.replace('git://', 'https://') # url = url.replace('https://', 'https://raw.') return url def convert_source(dist_name): url = BASE_SRC_URL + '/releases/%s-devel.yaml' % dist_name print('Load "%s"' % url) yaml_str = load_url(url) input_ = yaml.load(yaml_str) output = {} output['type'] = 'source' output['version'] = 1 output['repositories'] = {} for repo_name in sorted(input_['repositories']): input_repo = input_['repositories'][repo_name] output_repo = {} output_repo['type'] = input_repo['type'] output_repo['url'] = input_repo['url'] output_repo['version'] = input_repo['version'] if output_repo['type'] == 'svn' and output_repo['version'] is None: output_repo['version'] = 'HEAD' if output_repo['version'] is None: print('- "' + repo_name + '" has no version') del output_repo['version'] output['repositories'][repo_name] = output_repo yaml_str = yaml.dump(output, default_flow_style=False) yaml_str = yaml_str.replace(': null', ':') with open(dist_name + '/source.yaml', 'w') as f: f.write('%YAML 1.1\n') f.write('# ROS source file\n') f.write('# see REP 137: http://ros.org/reps/rep-0137.html\n') f.write('---\n') f.write(yaml_str) def convert_doc(dist_name): base = tempfile.mktemp() rc = subprocess.call(['git', 'clone', '--depth', '0', 'git://github.com/ros/rosdistro.git', base]) if rc: print('Failed to checkout rosdistro repo', file=sys.stderr) shutil.rmtree(base) return doc_base = os.path.join(base, 'doc', dist_name) rosinstalls = {} rosinstall_depends = {} for filename in os.listdir(doc_base): if filename.endswith('.rosinstall'): name = os.path.splitext(os.path.basename(filename))[0] with open(os.path.join(doc_base, filename)) as f: data = yaml.load(f) if name.endswith('_depends'): rosinstall_depends[name] = data else: rosinstalls[name] = data shutil.rmtree(base) # currently no doc has depends in groovy and hydro # assert not rosinstall_depends output = {} output['type'] = 'doc' output['version'] = 1 output['repositories'] = {} for repo_name in sorted(rosinstalls.keys()): for input_repo in rosinstalls[repo_name]: output_repo = {} output_repo['type'] = input_repo.keys()[0] input_data = input_repo[output_repo['type']] output_repo['url'] = input_data['uri'] if 'version' in input_data: output_repo['version'] = input_data['version'] if output_repo['type'] == 'svn' and ('version' not in output_repo or output_repo['version'] is None): output_repo['version'] = 'HEAD' if 'version' not in output_repo or output_repo['version'] is None: print('- "' + repo_name + '" has no version') if 'version' in output_repo: del output_repo['version'] local_name = input_data['local-name'] if local_name in output['repositories']: if output_repo == output['repositories'][local_name]: print('- skip duplicate "%s"' % local_name) continue key = local_name i = 1 while key in output['repositories']: i += 1 key = local_name + '_%d' % i print('- duplicate: %s %s -> %s' % (repo_name, local_name, key)) if i > 1: # ignore duplicates print(' ignoring duplicate') continue output['repositories'][key] = output_repo yaml_str = yaml.dump(output, default_flow_style=False) yaml_str = yaml_str.replace(': null', ':') with open(dist_name + '/doc.yaml', 'w') as f: f.write('%YAML 1.1\n') f.write('# ROS doc file\n') f.write('# see REP 137: http://ros.org/reps/rep-0137.html\n') f.write('---\n') f.write(yaml_str) if __name__ == '__main__': targets = get_targets() for distro in ['groovy', 'hydro']: print('\nConverting "%s"\n' % distro) convert_release(distro, targets) convert_source(distro) convert_doc(distro) rosdistro-0.8.0/scripts/rosdistro_freeze_source000077500000000000000000000101321357352161700221430ustar00rootroot00000000000000#!/usr/bin/env python # Software License Agreement (BSD License) # # Copyright (c) 2016, Clearpath Robotics # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # * Redistributions in binary form must reproduce the above # copyright notice, this list of conditions and the following # disclaimer in the documentation and/or other materials provided # with the distribution. # * Neither the name of Open Source Robotics Foundation, Inc. nor # the names of its contributors may be used to endorse or promote # products derived from this software without specific prior # written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. from __future__ import print_function import argparse import os.path import sys from rosdistro import get_distribution from rosdistro.freeze_source import CONCURRENT_DEFAULT, freeze_distribution_sources from rosdistro.index import Index from rosdistro.writer import yaml_from_distribution_file import yaml def parse_args(args=sys.argv[1:]): parser = argparse.ArgumentParser( description=''' Freeze a rosdistro\'s source branch versions to hashes or tags. If neither --release-version nor --release-tag are specified, the hashes of the current devel branches are used. ''') parser.add_argument('index', type=argparse.FileType(), help='Path to a local index.yaml file.') parser.add_argument('dist_names', nargs='*', help='The names of the distributions (default: all)') parser.add_argument('-j', '--jobs', type=int, default=CONCURRENT_DEFAULT, help='How many worker threads to use.') parser.add_argument('-q', '--quiet', action='store_true', help='Suppress updating status bar (for script/CI usage).') mode = parser.add_mutually_exclusive_group() mode.add_argument('--release-version', action='store_true', help='Freeze to the hash of current release tag.') mode.add_argument('--release-tag', action='store_true', help='Freeze to name of current release tag.') return parser.parse_args(args) def main(): args = parse_args() index = Index( yaml.safe_load(args.index), 'file://%s' % os.path.dirname(os.path.abspath(args.index.name))) if not args.dist_names: args.dist_names = sorted(index.distributions.keys()) for dist_name in args.dist_names: dist_url = index.distributions[dist_name]['distribution'] if isinstance(dist_url, list): if len(dist_url) != 1: print('This script only works for distributions with a single distribution.yaml, ' 'skipping distribution "%s"' % dist_name, file=sys.stderr) continue dist_url = dist_url[0] dist = get_distribution(index, dist_name) freeze_distribution_sources( dist, release_version=args.release_version, release_tag=args.release_tag, concurrent_ops=args.jobs, quiet=args.quiet) with open(dist_url.split('://')[1], 'w') as f: f.write(yaml_from_distribution_file(dist)) if __name__ == '__main__': main() rosdistro-0.8.0/scripts/rosdistro_generate_cache000077500000000000000000000014211357352161700222210ustar00rootroot00000000000000#!/usr/bin/env python import optparse import sys import rosdistro def gen_cache(options, args): # touch everything to create the new cache distro = rosdistro.RosDistro(args[0], options.cache) for r in distro.get_repositories(): print("Caching %s" % r) distro.get_depends1(r) print("Cache written to %s" % (distro.depends_file.local_url)) def main(): parser = optparse.OptionParser() parser.add_option("--cache", action="store", default=None) (options, args) = parser.parse_args() if len(args) != 1: print("Usage: %s ros_distro" % sys.argv[0]) return try: gen_cache(options, args) except Exception as e: print(e) print("Failure") return if __name__ == "__main__": main() rosdistro-0.8.0/scripts/rosdistro_migrate_to_rep_141000077500000000000000000000134761357352161700227060ustar00rootroot00000000000000#!/usr/bin/env python from __future__ import print_function import argparse import gzip import os try: from cStringIO import StringIO except ImportError: from io import BytesIO as StringIO from rosdistro.loader import load_url from rosdistro.verify import _to_yaml, _yaml_header_lines import yaml def migrate(index_yaml): data = yaml.load(open(index_yaml, 'r')) assert data['type'] == 'index' assert data['version'] == 1 data['version'] = 2 for distro_name in data['distributions']: distro_data = data['distributions'][distro_name] doc_file = distro_data['doc'] release_file = distro_data['release'] source_file = distro_data['source'] del distro_data['doc'] del distro_data['release'] del distro_data['source'] distribution_file = '%s/distribution.yaml' % distro_name distro_data['distribution'] = distribution_file generate_repos_file(index_yaml, distribution_file, doc_file, release_file, source_file) cache_url = distro_data['release_cache'] del distro_data['release_cache'] rel_cache_file = os.path.join(distro_name, '%s-cache.yaml' % distro_name) distro_data['distribution_cache'] = rel_cache_file + '.gz' base = os.path.dirname(index_yaml) cache_file = os.path.join(base, rel_cache_file) update_cache(index_yaml, distro_name, cache_url, cache_file, distribution_file) data = index_to_yaml(data) data = '\n'.join(_yaml_header_lines('index', data['version'])) + '\n' + data with open(index_yaml + '.new', 'w') as f: f.write(data) def index_to_yaml(data): yaml_str = yaml.dump(data, default_flow_style=None) return yaml_str def generate_repos_file(index_yaml, repos_file, doc_file, release_file, source_file): base = os.path.dirname(index_yaml) repos_url = os.path.join(base, repos_file) doc_url = os.path.join(base, doc_file) release_url = os.path.join(base, release_file) source_url = os.path.join(base, source_file) generate_repos_url(repos_url, doc_url, release_url, source_url) def generate_repos_url(repos_url, doc_url, release_url, source_url): data = {} data['type'] = 'distribution' data['version'] = 1 data['repositories'] = {} # migrate release stuff release_data = yaml.load(open(release_url, 'r')) assert release_data['type'] == 'release' assert release_data['version'] == 1 data['release_platforms'] = release_data['platforms'] for repo_name in release_data['repositories']: repo_data = {} release_repo_data = release_data['repositories'][repo_name] repo_data['release'] = get_dict_parts(release_repo_data, ['tags', 'url', 'version']) if 'packages' in release_repo_data: pkgs = release_repo_data['packages'] pkg_names = pkgs.keys() if len(pkg_names) > 1 or (len(pkg_names) == 1 and pkg_names[0] != repo_name): repo_data['release']['packages'] = sorted(pkg_names) for pkg_name in pkgs: if pkgs[pkg_name] is not None: assert 'status' not in pkgs[pkg_name] assert 'status_description' not in pkgs[pkg_name] repo_data.update(get_dict_parts(release_repo_data, ['status', 'status_description'])) data['repositories'][repo_name] = repo_data # migrate doc stuff doc_data = yaml.load(open(doc_url, 'r')) assert doc_data['type'] == 'doc' assert doc_data['version'] == 1 for repo_name in doc_data['repositories']: doc_repo_data = doc_data['repositories'][repo_name] if repo_name not in data['repositories']: data['repositories'][repo_name] = {} data['repositories'][repo_name]['doc'] = get_dict_parts(doc_repo_data, ['type', 'url', 'version']) # migrate source stuff source_data = yaml.load(open(source_url, 'r')) assert source_data['type'] == 'source' assert source_data['version'] == 1 for repo_name in source_data['repositories']: source_repo_data = source_data['repositories'][repo_name] if repo_name not in data['repositories']: data['repositories'][repo_name] = {} data['repositories'][repo_name]['source'] = get_dict_parts(source_repo_data, ['type', 'url', 'version']) data = _to_yaml(data) data = '\n'.join(_yaml_header_lines('distribution', data['version'])) + '\n' + data with open(repos_url, 'w') as f: f.write(data) def update_cache(index_yaml, distro_name, cache_url, cache_file, distribution_file): base = os.path.dirname(index_yaml) assert cache_url.endswith('.gz') yaml_gz_str = load_url(cache_url, skip_decode=True) yaml_gz_stream = StringIO(yaml_gz_str) f = gzip.GzipFile(fileobj=yaml_gz_stream, mode='rb') yaml_str = f.read() if not isinstance(yaml_str, str): yaml_str = yaml_str.decode('utf-8') f.close() cache_data = yaml.load(yaml_str) del cache_data['release_file'] distribution_data = yaml.load(open(os.path.join(base, distribution_file), 'r')) cache_data['distribution_file'] = distribution_data cache_data['release_package_xmls'] = cache_data['package_xmls'] del cache_data['package_xmls'] cache_data['version'] = 2 data = _to_yaml(cache_data) data = '\n'.join(_yaml_header_lines('cache', cache_data['version'])) + '\n' + data with open(cache_file, 'w') as f: f.write(data) with gzip.open(cache_file + '.gz', 'wb') as f: f.write(data) def get_dict_parts(d, keys): data = {} for key in keys: if key in d: data[key] = d[key] return data if __name__ == "__main__": parser = argparse.ArgumentParser(description='Migrate the distros from REP 137 to REP 141.') parser.add_argument('index', help='The index.yaml file to migrate') args = parser.parse_args() migrate(args.index) rosdistro-0.8.0/scripts/rosdistro_migrate_to_rep_143000077500000000000000000000022231357352161700226740ustar00rootroot00000000000000#!/usr/bin/env python from __future__ import print_function import argparse from rosdistro.verify import _yaml_header_lines import yaml def migrate(index_yaml): data = yaml.load(open(index_yaml, 'r')) assert data['type'] == 'index' assert data['version'] == 2 data['version'] = 3 for distro_name in data['distributions']: distro_data = data['distributions'][distro_name] distro_data['distribution'] = [distro_data['distribution']] for key in ['doc_builds', 'release_builds', 'source_builds']: if key in distro_data: del distro_data[key] yaml_str = index_to_yaml(data) yaml_str = '\n'.join(_yaml_header_lines('index', data['version'])) + '\n' + yaml_str with open(index_yaml + '.new', 'w') as f: f.write(yaml_str) def index_to_yaml(data): yaml_str = yaml.dump(data, default_flow_style=None) return yaml_str if __name__ == "__main__": parser = argparse.ArgumentParser(description='Migrate the distros from REP 141 to REP 143.') parser.add_argument('index', help='The index.yaml file to migrate') args = parser.parse_args() migrate(args.index) rosdistro-0.8.0/scripts/rosdistro_reformat000077500000000000000000000051211357352161700211240ustar00rootroot00000000000000#!/usr/bin/env python # Software License Agreement (BSD License) # # Copyright (c) 2013, Open Source Robotics Foundation, Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # * Redistributions in binary form must reproduce the above # copyright notice, this list of conditions and the following # disclaimer in the documentation and/or other materials provided # with the distribution. # * Neither the name of Open Source Robotics Foundation, Inc. nor # the names of its contributors may be used to endorse or promote # products derived from this software without specific prior # written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. import argparse import os import sys from rosdistro.verify import reformat_files from rosdistro.verify import verify_files_identical def parse_args(args=sys.argv[1:]): parser = argparse.ArgumentParser( description='Reformat the rosdistro files by reading and overwriting each file referenced from the index.' ) add = parser.add_argument add( 'index', help='The path or url of the index.yaml file (must be either a local file or a file:// url)') add( '-n', '--dry-run', action='store_true', help="Don't actually overwrite any files, just show what would be done.") return parser.parse_args(args) if __name__ == '__main__': args = parse_args() index = args.index if os.path.isfile(index): index = 'file://' + os.path.abspath(index) if args.dry_run: success = verify_files_identical(index) else: success = reformat_files(index) sys.exit(0 if success else 1) rosdistro-0.8.0/setup.cfg000066400000000000000000000002541357352161700154030ustar00rootroot00000000000000[build_sphinx] source-dir = doc/ build-dir = doc/build all_files = 1 [upload_sphinx] upload-dir = doc/build/html [nosetests] with-coverage=true cover-package=rosdistro rosdistro-0.8.0/setup.py000077500000000000000000000032101357352161700152720ustar00rootroot00000000000000#!/usr/bin/env python import os import sys from setuptools import find_packages, setup kwargs = { 'name': 'rosdistro', # same version as in: # - src/rosdistro/__init__.py # - stdeb.cfg 'version': '0.8.0', 'install_requires': ['PyYAML', 'setuptools'], 'packages': find_packages('src'), 'package_dir': {'': 'src'}, 'scripts': [ # 'scripts/rosdistro', 'scripts/rosdistro_build_cache', 'scripts/rosdistro_freeze_source', # 'scripts/rosdistro_convert', # 'scripts/rosdistro_generate_cache', 'scripts/rosdistro_migrate_to_rep_141', 'scripts/rosdistro_migrate_to_rep_143', 'scripts/rosdistro_reformat' ], 'author': 'Wim Meeussen, Dirk Thomas', 'author_email': 'wim@hidof.com, dthomas@osrfoundation.org', 'maintainer': 'Dirk Thomas', 'maintainer_email': 'dthomas@osrfoundation.org', 'url': 'http://wiki.ros.org/rosdistro', 'keywords': ['ROS'], 'classifiers': [ 'Programming Language :: Python', 'License :: OSI Approved :: BSD License', 'License :: OSI Approved :: MIT License'], 'description': 'A tool to work with rosdistro files', 'long_description': 'A tool to work with rosdistro files', 'license': 'BSD, MIT' } if sys.version_info[0] == 2 and sys.version_info[1] < 7: kwargs['install_requires'].append('argparse') if 'SKIP_PYTHON_MODULES' in os.environ: kwargs['packages'] = [] kwargs['package_dir'] = {} elif 'SKIP_PYTHON_SCRIPTS' in os.environ: kwargs['name'] += '_modules' kwargs['scripts'] = [] else: kwargs['install_requires'] += ['catkin_pkg', 'rospkg'] setup(**kwargs) rosdistro-0.8.0/src/000077500000000000000000000000001357352161700143505ustar00rootroot00000000000000rosdistro-0.8.0/src/rosdistro/000077500000000000000000000000001357352161700164005ustar00rootroot00000000000000rosdistro-0.8.0/src/rosdistro/__init__.py000066400000000000000000000165261357352161700205230ustar00rootroot00000000000000# Software License Agreement (BSD License) # # Copyright (c) 2013, Open Source Robotics Foundation, Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # * Redistributions in binary form must reproduce the above # copyright notice, this list of conditions and the following # disclaimer in the documentation and/or other materials provided # with the distribution. # * Neither the name of Open Source Robotics Foundation, Inc. nor # the names of its contributors may be used to endorse or promote # products derived from this software without specific prior # written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. from __future__ import print_function import gzip import logging import os try: from cStringIO import StringIO except ImportError: from io import BytesIO as StringIO try: from urllib.parse import urlparse except ImportError: from urlparse import urlparse import yaml logger = logging.getLogger('rosdistro') from .distribution import Distribution # noqa from .distribution_cache import DistributionCache # noqa from .distribution_file import DistributionFile # noqa from .distribution_file import create_distribution_file # noqa from .external.appdirs import site_config_dir, user_config_dir # noqa from .index import Index # noqa from .loader import load_url # noqa from .manifest_provider.cache import CachedManifestProvider, CachedSourceManifestProvider # noqa # same version as in: # - setup.py # - stdeb.cfg __version__ = '0.8.0' # index information DEFAULT_INDEX_URL = 'https://raw.githubusercontent.com/ros/rosdistro/master/index-v4.yaml' def get_index_url(): # environment variable has precedence over configuration files if 'ROSDISTRO_INDEX_URL' in os.environ: return os.environ['ROSDISTRO_INDEX_URL'] def read_cfg_index_url(fname): try: with open(fname) as f: return yaml.safe_load(f.read())['index_url'] except (IOError, KeyError, yaml.YAMLError): return None cfg_file = 'config.yaml' # first, look for the user configuration (usually ~/.config/rosdistro) user_cfg_path = os.path.join(user_config_dir('rosdistro'), cfg_file) index_url = read_cfg_index_url(user_cfg_path) if index_url is not None: return index_url # if not found, look for the global configuration *usually /etc/xdg/rosdistro) site_cfg_paths = os.path.join(site_config_dir('rosdistro', multipath=True), cfg_file).split(os.pathsep) for site_cfg_path in site_cfg_paths: index_url = read_cfg_index_url(site_cfg_path) if index_url is not None: return index_url # if nothing is found, use the default return DEFAULT_INDEX_URL def get_index(url): logger.debug('Load index from "%s"' % url) yaml_str = load_url(url) data = yaml.safe_load(yaml_str) base_url = os.path.dirname(url) url_parts = urlparse(url) return Index(data, base_url, url_query=url_parts.query) # distribution information def get_distribution(index, dist_name): dist_file = get_distribution_file(index, dist_name) return Distribution(dist_file) def get_distribution_file(index, dist_name): data = _get_dist_file_data(index, dist_name, 'distribution') return create_distribution_file(dist_name, data) def get_distribution_files(index, dist_name): data = _get_dist_file_data(index, dist_name, 'distribution') if not isinstance(data, list): data = [data] dist_files = [] for d in data: dist_file = DistributionFile(dist_name, d) dist_files.append(dist_file) return dist_files def get_cached_distribution(index, dist_name, cache=None, allow_lazy_load=False): if cache is None: try: cache = get_distribution_cache(index, dist_name) except Exception: if not allow_lazy_load: raise # create empty cache instance dist_file_data = _get_dist_file_data(index, dist_name, 'distribution') cache = DistributionCache(dist_name, distribution_file_data=dist_file_data) dist = Distribution( cache.distribution_file, [CachedManifestProvider(cache, Distribution.default_manifest_providers if allow_lazy_load else None)], [CachedSourceManifestProvider(cache, Distribution.default_source_manifest_providers if allow_lazy_load else None)]) assert cache.distribution_file.name == dist_name return dist def get_distribution_cache_string(index, dist_name): if dist_name not in index.distributions.keys(): raise RuntimeError("Unknown distribution: '{0}'. Valid distribution names are: {1}".format(dist_name, ', '.join(sorted(index.distributions.keys())))) dist = index.distributions[dist_name] if 'distribution_cache' not in dist.keys(): raise RuntimeError("Distribution has no cache: '{0}'".format(dist_name)) url = dist['distribution_cache'] logger.debug('Load cache from "%s"' % url) if url.endswith('.yaml'): yaml_str = load_url(url) elif url.endswith('.yaml.gz'): yaml_gz_str = load_url(url, skip_decode=True) yaml_gz_stream = StringIO(yaml_gz_str) f = gzip.GzipFile(fileobj=yaml_gz_stream, mode='rb') yaml_str = f.read() f.close() if not isinstance(yaml_str, str): yaml_str = yaml_str.decode('utf-8') else: raise NotImplementedError('The url of the cache must end with either ".yaml" or ".yaml.gz"') return yaml_str def get_distribution_cache(index, dist_name): yaml_str = get_distribution_cache_string(index, dist_name) data = yaml.safe_load(yaml_str) return DistributionCache(dist_name, data) # internal def _get_dist_file_data(index, dist_name, type_): if dist_name not in index.distributions.keys(): raise RuntimeError("Unknown release: '{0}'. Valid release names are: {1}".format(dist_name, ', '.join(sorted(index.distributions.keys())))) dist = index.distributions[dist_name] if type_ not in dist.keys(): raise RuntimeError('unknown release type "%s"' % type_) url = dist[type_] def _load_yaml_data(url): logger.debug('Load file from "%s"' % url) yaml_str = load_url(url) return yaml.safe_load(yaml_str) if not isinstance(url, list): data = _load_yaml_data(url) else: data = [] for u in url: data.append(_load_yaml_data(u)) return data from .legacy import * # noqa rosdistro-0.8.0/src/rosdistro/aptdistro.py000066400000000000000000000036071357352161700207710ustar00rootroot00000000000000try: from urllib2 import urlopen except ImportError: from urllib.request import urlopen class AptDistro: def __init__(self, ubuntudistro, arch, shadow=True): if shadow: url = 'http://packages.ros.org/ros-shadow-fixed/ubuntu/dists/{0}/main/binary-{1}/Packages' url = urlopen(url.format(ubuntudistro, arch)) else: url = 'http://packages.ros.org/ros/ubuntu/dists/{0}/main/binary-{1}/Packages' url = urlopen(url.format(ubuntudistro, arch)) self.dep = {} package = None for l in url.read().split('\n'): if l.startswith('Package: '): package = l[len('Package: '):] if l.startswith('Depends: '): if not package: raise RuntimeError("Found 'Depends: ' but not 'Package: ' while parsing the apt repository index file") self.dep[package] = [d.split(' ')[0] for d in (l[len('Depends: '):].split(', '))] package = None def has_package(self, package): return package in self.dep def depends1(self, package): return self.depends(package, one=True) def depends(self, package, res=None, one=False): if res is None: res = [] if package in self.dep: for d in self.dep[package]: if d not in res: res.append(d) if not one: self.depends(d, res, one) return res def depends_on1(self, package): return self.depends_on(package, one=True) def depends_on(self, package, res=None, one=False): if res is None: res = [] for p, dep in self.dep.iteritems(): if package in dep: if p not in res: res.append(p) if not one: self.depends_on(p, res, one) return res rosdistro-0.8.0/src/rosdistro/common.py000066400000000000000000000012461357352161700202450ustar00rootroot00000000000000from __future__ import print_function import sys _quiet = False def quiet(state=True): global _quiet _quiet = state def _print_func(msg, end, file): global _quiet if not _quiet: print(msg, end=end, file=file) def override_print(print_func=_print_func): global _print _print = print_func _print = _print_func def info(msg, end=None, file=None): global _print _print(msg, end=end, file=file) def warning(msg, end=None, file=None): global _print _print(msg, end=end, file=file) def error(msg, end=None, file=None): global _print file = sys.stderr if file is None else file _print(msg, end=end, file=file) rosdistro-0.8.0/src/rosdistro/dependency_walker.py000066400000000000000000000170271357352161700224440ustar00rootroot00000000000000# Software License Agreement (BSD License) # # Copyright (c) 2013, Open Source Robotics Foundation, Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # * Redistributions in binary form must reproduce the above # copyright notice, this list of conditions and the following # disclaimer in the documentation and/or other materials provided # with the distribution. # * Neither the name of Open Source Robotics Foundation, Inc. nor # the names of its contributors may be used to endorse or promote # products derived from this software without specific prior # written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. from catkin_pkg.package import InvalidPackage, parse_package_string class DependencyWalker(object): def __init__(self, distribution_instance, evaluate_condition_context=None): self._distribution_instance = distribution_instance self._packages = {} self._evaluate_condition_context = evaluate_condition_context def _get_package(self, pkg_name): if pkg_name not in self._packages: repo = self._distribution_instance.repositories[self._distribution_instance.release_packages[pkg_name].repository_name].release_repository assert repo is not None and repo.version is not None, "Package '%s' in repository '%s' has no version set" % (pkg_name, repo.name) assert 'release' in repo.tags, "Package '%s' in repository '%s' has no 'release' tag set" % (pkg_name, repo.name) pkg_xml = self._distribution_instance.get_release_package_xml(pkg_name) try: pkg = parse_package_string(pkg_xml) except InvalidPackage as e: raise InvalidPackage(pkg_name + ': %s' % str(e)) else: if self._evaluate_condition_context is not None: pkg.evaluate_conditions(self._evaluate_condition_context) self._packages[pkg_name] = pkg return self._packages[pkg_name] def _get_package_names(self): return self._distribution_instance.release_packages.keys() def get_depends(self, pkg_name, depend_type, ros_packages_only=False): '''Return a set of package names which the package depends on.''' deps = self._get_dependencies(pkg_name, depend_type) if ros_packages_only: deps &= set(self._get_package_names()) return deps def get_recursive_depends(self, pkg_name, depend_types, ros_packages_only=False, ignore_pkgs=None, limit_depth=None): '''Return a set of package names which the package (transitively) depends on.''' ignore_pkgs = set(ignore_pkgs or []) depends = set([]) # mapping from the scheduled pkg names to their dependency level pkgs_to_check = {pkg_name: 0} while pkgs_to_check: next_pkg_to_check = sorted(pkgs_to_check.keys())[0] current_level = pkgs_to_check.pop(next_pkg_to_check) if next_pkg_to_check in ignore_pkgs or (limit_depth is not None and current_level >= limit_depth): continue for depend_type in depend_types: deps = self.get_depends(next_pkg_to_check, depend_type, ros_packages_only=ros_packages_only) deps -= ignore_pkgs new_deps = deps - depends for new_dep in new_deps: if new_dep not in pkgs_to_check: pkgs_to_check[new_dep] = current_level + 1 else: pkgs_to_check[new_dep] = min(pkgs_to_check[new_dep], current_level + 1) depends |= new_deps return depends def get_depends_on(self, pkg_name, depend_type, ignore_pkgs=None): '''Return a set of package names which depend on the package.''' ignore_pkgs = ignore_pkgs or [] depends_on = set([]) for name in self._get_package_names(): if name in ignore_pkgs: continue repo = self._get_package_repo(name) if repo is None or repo.version is None: continue deps = self._get_dependencies(name, depend_type) if pkg_name in deps: depends_on.add(name) return depends_on def get_recursive_depends_on(self, pkg_name, depend_types, ignore_pkgs=None): '''Return a set of package names which (transitively) depend on the package.''' ignore_pkgs = ignore_pkgs or [] depends_on = set([]) pkgs_to_check = set([pkg_name]) while pkgs_to_check: next_pkg_to_check = pkgs_to_check.pop() for depend_type in depend_types: deps = self.get_depends_on(next_pkg_to_check, depend_type, ignore_pkgs=ignore_pkgs) new_deps = deps - depends_on pkgs_to_check |= new_deps depends_on |= new_deps return depends_on def _get_dependencies(self, pkg_name, dep_type): pkg = self._get_package(pkg_name) deps = { 'build': pkg.build_depends, 'buildtool': pkg.buildtool_depends, 'build_export': pkg.build_export_depends, 'buildtool_export': pkg.buildtool_export_depends, 'exec': pkg.exec_depends, 'run': pkg.run_depends, 'test': pkg.test_depends, 'doc': pkg.doc_depends, } return set([d.name for d in deps[dep_type] if d.evaluated_condition is not False]) def _get_package_repo(self, name): return self._distribution_instance.repositories[self._distribution_instance.release_packages[name].repository_name].release_repository class SourceDependencyWalker(DependencyWalker): def _get_package(self, pkg_name): if pkg_name not in self._packages: repo = self._distribution_instance.repositories[self._distribution_instance.source_packages[pkg_name].repository_name].source_repository assert repo is not None, "Package '%s' in repository '%s' is missing a source entry." % (pkg_name, repo.name) pkg_xml = self._distribution_instance.get_source_package_xml(pkg_name) try: pkg = parse_package_string(pkg_xml) except InvalidPackage as e: raise InvalidPackage(pkg_name + ': %s' % str(e)) self._packages[pkg_name] = pkg return self._packages[pkg_name] def _get_package_names(self): return self._distribution_instance.source_packages.keys() def _get_package_repo(self, name): return self._distribution_instance.repositories[self._distribution_instance.source_packages[name].repository_name].source_repository rosdistro-0.8.0/src/rosdistro/develdistro.py000066400000000000000000000023571357352161700213050ustar00rootroot00000000000000try: from urllib.request import urlopen except ImportError: from urllib2 import urlopen import yaml class DevelDistro: def __init__(self, name): url = urlopen('https://raw.github.com/ros/rosdistro/master/releases/{0}-devel.yaml'.format(name)) distro = yaml.load(url.read())['repositories'] self.repositories = {} for name, data in distro.iteritems(): repo = DevelDistroRepo(name, data) self.repositories[name] = repo class DevelDistroRepo: def __init__(self, name, data): self.name = name self.type = data['type'] self.url = data['url'] self.version = None if 'version' in data: self.version = data['version'] def get_rosinstall(self): if self.version: return yaml.dump([{ self.type: { 'local-name': self.name, 'uri': '{0}'.format(self.url), 'version': '{0}'.format(self.version) }}], default_style=False) else: return yaml.dump([{ self.type: { 'local-name': self.name, 'uri': '{0}'.format(self.url) }}], default_style=False) rosdistro-0.8.0/src/rosdistro/distribution.py000066400000000000000000000114251357352161700214740ustar00rootroot00000000000000# Software License Agreement (BSD License) # # Copyright (c) 2013, Open Source Robotics Foundation, Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # * Redistributions in binary form must reproduce the above # copyright notice, this list of conditions and the following # disclaimer in the documentation and/or other materials provided # with the distribution. # * Neither the name of Open Source Robotics Foundation, Inc. nor # the names of its contributors may be used to endorse or promote # products derived from this software without specific prior # written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. from .manifest_provider.bitbucket import bitbucket_manifest_provider from .manifest_provider.git import git_manifest_provider, git_source_manifest_provider from .manifest_provider.github import github_manifest_provider, github_source_manifest_provider from .package import Package class Distribution(object): default_manifest_providers = [github_manifest_provider, bitbucket_manifest_provider, git_manifest_provider] default_source_manifest_providers = [github_source_manifest_provider, git_source_manifest_provider] def __init__(self, distribution_file, manifest_providers=None, source_manifest_providers=None): self._distribution_file = distribution_file # Use default self._manifest_providers = Distribution.default_manifest_providers self._source_manifest_providers = Distribution.default_source_manifest_providers # Override default if given if manifest_providers is not None: self._manifest_providers = manifest_providers if source_manifest_providers is not None: self._source_manifest_providers = source_manifest_providers self._release_package_xmls = {} self._source_repo_package_xmls = {} def __getattr__(self, name): return getattr(self._distribution_file, name) def get_release_package_xml(self, pkg_name): if pkg_name not in self._release_package_xmls: pkg = self._distribution_file.release_packages[pkg_name] repo_name = pkg.repository_name repo = self._distribution_file.repositories[repo_name] if repo.release_repository is None: return None repo = repo.release_repository if repo.version is None: return None package_xml = None for mp in self._manifest_providers: package_xml = mp(self._distribution_file.name, repo, pkg_name) if package_xml is not None: break self._release_package_xmls[pkg_name] = package_xml return self._release_package_xmls[pkg_name] def get_source_package_xml(self, pkg_name): repo_name = self._distribution_file.source_packages[pkg_name].repository_name repo_cache = self.get_source_repo_package_xmls(repo_name) if repo_cache: return repo_cache[pkg_name][1] else: return None def get_source_repo_package_xmls(self, repo_name): if repo_name in self._source_repo_package_xmls: return self._source_repo_package_xmls[repo_name] else: for mp in self._source_manifest_providers: repo_cache = mp(self.repositories[repo_name].source_repository) if repo_cache is not None: # Update map of package XMLs, and also list of known package names. self._source_repo_package_xmls[repo_name] = repo_cache for pkg_name in repo_cache: if pkg_name[0] != '_': self._distribution_file.source_packages[pkg_name] = Package(pkg_name, repo_name) return self._source_repo_package_xmls[repo_name] return None rosdistro-0.8.0/src/rosdistro/distribution_cache.py000066400000000000000000000233471357352161700226250ustar00rootroot00000000000000# Software License Agreement (BSD License) # # Copyright (c) 2013, Open Source Robotics Foundation, Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # * Redistributions in binary form must reproduce the above # copyright notice, this list of conditions and the following # disclaimer in the documentation and/or other materials provided # with the distribution. # * Neither the name of Open Source Robotics Foundation, Inc. nor # the names of its contributors may be used to endorse or promote # products derived from this software without specific prior # written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. from __future__ import print_function import sys from . import logger from .distribution_file import create_distribution_file from .package import Package from .source_repository_cache import SourceRepositoryCache from .vcs import Git, ref_is_hash class DistributionCache(object): _type = 'cache' def __init__(self, name, data=None, distribution_file_data=None): assert data or distribution_file_data if data: assert 'type' in data, "Expected file type is '%s'" % DistributionCache._type assert data['type'] == DistributionCache._type, "Expected file type is '%s', not '%s'" % (DistributionCache._type, data['type']) assert 'version' in data, "Distribution cache file for '%s' lacks required version information" % name self.version = int(data['version']) assert self.version > 1, "Unable to handle '%s' format version '%d' anymore, please update your '%s' file to version '2'" % (DistributionCache._type, self.version, DistributionCache._type) assert self.version == 2, "Unable to handle '%s' format version '%d', please update rosdistro (e.g. on Ubuntu/Debian use: sudo apt-get update && sudo apt-get install --only-upgrade python-rosdistro)" % (DistributionCache._type, self.version) assert 'name' in data, "Distribution cache file for '%s' lacks required name information" % name assert data['name'] == name, "Distribution cache file for '%s' does not match the name '%s'" % (name, data['name']) else: self.version = 2 self._distribution_file_data = data['distribution_file'] if data else distribution_file_data self.distribution_file = create_distribution_file(name, self._distribution_file_data) self.release_package_xmls = data['release_package_xmls'] if data else {} self.source_repo_package_xmls = {} if data and 'source_repo_package_xmls' in data: for repo_name, repo_data in data['source_repo_package_xmls'].items(): self.source_repo_package_xmls[repo_name] = SourceRepositoryCache(repo_data) self.distribution_file.source_packages = self.get_source_packages() # if Python 2 has converted the xml to unicode, convert it back for k, v in self.release_package_xmls.items(): if not isinstance(v, str) and not isinstance(v, bytes): self.release_package_xmls[k] = v.encode('utf-8') def get_data(self): data = {} data['type'] = 'cache' data['version'] = 2 data['name'] = self.distribution_file.name data['distribution_file'] = self._distribution_file_data data['release_package_xmls'] = self.release_package_xmls data['source_repo_package_xmls'] = dict([(repo_name, repo_cache.get_data()) for repo_name, repo_cache in self.source_repo_package_xmls.items()]) return data def update_distribution(self, distribution_file_data): # remove packages which are not in the old distribution file self._remove_obsolete_entries() # determine differences in doc and source entries if len(distribution_file_data) == len(self._distribution_file_data): for old_data, new_data in zip(self._distribution_file_data, distribution_file_data): if not new_data['repositories']: continue for repo_name in sorted(new_data['repositories'].keys()): repo = new_data['repositories'][repo_name] for section in ['doc', 'source']: if section not in repo: continue if repo_name in (old_data['repositories'] or []) and \ section in old_data['repositories'][repo_name] and \ old_data['repositories'][repo_name][section] == repo[section]: continue # section is either different or does't exist before print(" - updated '%s' entry for repository '%s'" % (section, repo_name)) self._distribution_file_data = distribution_file_data dist_file = create_distribution_file(self.distribution_file.name, self._distribution_file_data) # remove all release package xmls where the package version has changed. print("- removing invalid release package cache entries.") for pkg_name in sorted(dist_file.release_packages.keys()): if pkg_name not in self.distribution_file.release_packages: continue if pkg_name in self.release_package_xmls and self._get_repo_info(dist_file, pkg_name) != self._get_repo_info(self.distribution_file, pkg_name): logger.debug("Dropping release package XML cache for %s" % pkg_name) del self.release_package_xmls[pkg_name] # Remove all source package xmls where the devel branch is pointing to a different commit than # the one we have associated with our cache. This requires calling git ls-remote on all affected repos. if self.source_repo_package_xmls: print("- checking invalid source repo cache entries.") for repo in sorted(self.source_repo_package_xmls.keys()): sys.stdout.write('.') sys.stdout.flush() try: source_repository = dist_file.repositories[repo].source_repository except (KeyError, AttributeError): # The repo entry has been dropped, or the source stanza from it has been dropped, # either way, remove the cache entries associated with this repository. logger.debug('Unable to find source repository info for repo "%s".' % repo) del self.source_repo_package_xmls[repo] continue if ref_is_hash(source_repository.version): source_hash = source_repository.version else: result = Git().command('ls-remote', source_repository.url, source_repository.version) if result['returncode'] != 0 or not result['output']: # Error checking remote, or unable to find remote reference. Drop the cache entry. logger.debug("Unable to check hash for branch %s of %s, dropping cache entry." % (source_repository.version, source_repository.url)) del self.source_repo_package_xmls[repo] continue # Split by line first and take the last line, to squelch any preamble output, for example # a known host key validation notice. source_hash = result['output'].split('\n')[-1].split('\t')[0] cached_hash = self.source_repo_package_xmls[repo].ref() if source_hash != cached_hash: logger.debug('Repo "%s" has moved from %s to %s, dropping cache.' % (repo, cached_hash, source_hash)) del self.source_repo_package_xmls[repo] sys.stdout.write('\n') self.distribution_file = dist_file self.distribution_file.source_packages = self.get_source_packages() # remove packages which are not in the new distribution file self._remove_obsolete_entries() def get_source_packages(self): """ Returns dictionary mapping source package names to Package() objects. """ package_dict = {} for source_repo_name, source_repo in self.source_repo_package_xmls.items(): for pkg_name in source_repo: package_dict[pkg_name] = Package(pkg_name, source_repo_name) return package_dict def _get_repo_info(self, dist_file, pkg_name): pkg = dist_file.release_packages[pkg_name] repo = dist_file.repositories[pkg.repository_name].release_repository return (repo.version, repo.url) def _remove_obsolete_entries(self): for pkg_name in list(self.release_package_xmls.keys()): if pkg_name not in self.distribution_file.release_packages: print('- REMOVE', pkg_name) del self.release_package_xmls[pkg_name] rosdistro-0.8.0/src/rosdistro/distribution_cache_generator.py000066400000000000000000000220111357352161700246560ustar00rootroot00000000000000# Software License Agreement (BSD License) # # Copyright (c) 2013, Open Source Robotics Foundation, Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # * Redistributions in binary form must reproduce the above # copyright notice, this list of conditions and the following # disclaimer in the documentation and/or other materials provided # with the distribution. # * Neither the name of Open Source Robotics Foundation, Inc. nor # the names of its contributors may be used to endorse or promote # products derived from this software without specific prior # written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. from __future__ import print_function import gzip import os import re import sys from catkin_pkg.package import InvalidPackage, parse_package_string import yaml from . import _get_dist_file_data, get_cached_distribution, get_distribution_cache, get_index from .distribution_cache import DistributionCache def generate_distribution_caches( index, dist_names=None, preclean=False, ignore_local=False, include_source=False, debug=False ): if os.path.isfile(index): index = 'file://' + os.path.abspath(index) index = get_index(index) if not dist_names: dist_names = sorted(index.distributions.keys()) errors = [] caches = {} for dist_name in dist_names: try: cache = generate_distribution_cache( index, dist_name, preclean=preclean, ignore_local=ignore_local, include_source=include_source, debug=debug) except RuntimeError as e: errors.append(str(e)) continue caches[dist_name] = cache if errors: raise RuntimeError('\n'.join(errors)) return caches def generate_distribution_cache(index, dist_name, preclean=False, ignore_local=False, include_source=False, debug=False): dist, cache = _get_cached_distribution( index, dist_name, preclean=preclean, ignore_local=ignore_local, include_source=include_source) print('- fetch missing release manifests') errors = [] for pkg_name in sorted(dist.release_packages.keys()): repo = dist.repositories[dist.release_packages[pkg_name].repository_name].release_repository if repo.version is None: if debug: print(' - skip "%s" since it has no version' % pkg_name) continue if debug: print(' - fetch "%s"' % pkg_name) else: sys.stdout.write('.') sys.stdout.flush() # check that package.xml is fetchable old_package_xml = None if cache and pkg_name in cache.release_package_xmls: old_package_xml = cache.release_package_xmls[pkg_name] package_xml = dist.get_release_package_xml(pkg_name) if not package_xml: errors.append('%s: missing package.xml file for package "%s"' % (dist_name, pkg_name)) continue # check that package.xml is parseable try: pkg = parse_package_string(package_xml) except InvalidPackage as e: errors.append('%s: invalid package.xml file for package "%s": %s' % (dist_name, pkg_name, e)) continue # check that version numbers match (at least without deb inc) if not re.match('^%s(-[\dA-z~\+\.]+)?$' % re.escape(pkg.version), repo.version): errors.append('%s: different version in package.xml (%s) for package "%s" than for the repository (%s) (after removing the debian increment)' % (dist_name, pkg.version, pkg_name, repo.version)) if package_xml != old_package_xml: print(" - updated manifest of package '%s' to version '%s'" % (pkg_name, pkg.version)) if not debug: print('') if include_source: print('- fetch source repository manifests') for repo_name in sorted(dist.repositories.keys()): if dist.repositories[repo_name].source_repository: dist.get_source_repo_package_xmls(repo_name) if debug: print(' - fetch "%s"' % repo_name) else: sys.stdout.write('.') sys.stdout.flush() else: if debug: print(' - skip "%s" since it has no source entry.' % repo_name) continue if not debug: print('') if errors: raise RuntimeError('\n'.join(errors)) return cache class CacheYamlDumper(yaml.SafeDumper): """ A yaml dumper specific to dumping the serialized rosdistro cache file. Allows long lines and direct unicode representation. This avoids writing escape sequences, line continuations, and other noise into the cache file. Also permits long strings to alias each other (by default only objects do). """ def __init__(self, *args, **kwargs): kwargs['width'] = 10000 kwargs['allow_unicode'] = True super(CacheYamlDumper, self).__init__(*args, **kwargs) def ignore_aliases(self, content): """ Allow strings that look like package XML to alias to each other in the YAML output. """ try: basestring except NameError: # Python 3 basestring = str return not (isinstance(content, basestring) and ' for details and usage. """ # Dev Notes: # - MSDN on where to store app data files: # http://support.microsoft.com/default.aspx?scid=kb;en-us;310294#XSLTH3194121123120121120120 # - Mac OS X: http://developer.apple.com/documentation/MacOSX/Conceptual/BPFileSystem/index.html # - XDG spec for Un*x: http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html __version_info__ = (1, 3, 0) __version__ = '.'.join(map(str, __version_info__)) import sys import os PY3 = sys.version_info[0] == 3 if PY3: unicode = str def user_data_dir(appname=None, appauthor=None, version=None, roaming=False): r"""Return full path to the user-specific data dir for this application. "appname" is the name of application. If None, just the system directory is returned. "appauthor" (only required and used on Windows) is the name of the appauthor or distributing body for this application. Typically it is the owning company name. This falls back to appname. "version" is an optional version path element to append to the path. You might want to use this if you want multiple versions of your app to be able to run independently. If used, this would typically be ".". Only applied when appname is present. "roaming" (boolean, default False) can be set True to use the Windows roaming appdata directory. That means that for users on a Windows network setup for roaming profiles, this user data will be sync'd on login. See for a discussion of issues. Typical user data directories are: Mac OS X: ~/Library/Application Support/ Unix: ~/.local/share/ # or in $XDG_DATA_HOME, if defined Win XP (not roaming): C:\Documents and Settings\\Application Data\\ Win XP (roaming): C:\Documents and Settings\\Local Settings\Application Data\\ Win 7 (not roaming): C:\Users\\AppData\Local\\ Win 7 (roaming): C:\Users\\AppData\Roaming\\ For Unix, we follow the XDG spec and support $XDG_DATA_HOME. That means, by deafult "~/.local/share/". """ if sys.platform == "win32": if appauthor is None: appauthor = appname const = roaming and "CSIDL_APPDATA" or "CSIDL_LOCAL_APPDATA" path = os.path.normpath(_get_win_folder(const)) if appname: path = os.path.join(path, appauthor, appname) elif sys.platform == 'darwin': path = os.path.expanduser('~/Library/Application Support/') if appname: path = os.path.join(path, appname) else: path = os.getenv('XDG_DATA_HOME', os.path.expanduser("~/.local/share")) if appname: path = os.path.join(path, appname) if appname and version: path = os.path.join(path, version) return path def site_data_dir(appname=None, appauthor=None, version=None, multipath=False): """Return full path to the user-shared data dir for this application. "appname" is the name of application. If None, just the system directory is returned. "appauthor" (only required and used on Windows) is the name of the appauthor or distributing body for this application. Typically it is the owning company name. This falls back to appname. "version" is an optional version path element to append to the path. You might want to use this if you want multiple versions of your app to be able to run independently. If used, this would typically be ".". Only applied when appname is present. "multipath" is an optional parameter only applicable to *nix which indicates that the entire list of data dirs should be returned. By default, the first item from XDG_DATA_DIRS is returned, or '/usr/local/share/', if XDG_DATA_DIRS is not set Typical user data directories are: Mac OS X: /Library/Application Support/ Unix: /usr/local/share/ or /usr/share/ Win XP: C:\Documents and Settings\All Users\Application Data\\ Vista: (Fail! "C:\ProgramData" is a hidden *system* directory on Vista.) Win 7: C:\ProgramData\\ # Hidden, but writeable on Win 7. For Unix, this is using the $XDG_DATA_DIRS[0] default. WARNING: Do not use this on Windows. See the Vista-Fail note above for why. """ if sys.platform == "win32": if appauthor is None: appauthor = appname path = os.path.normpath(_get_win_folder("CSIDL_COMMON_APPDATA")) if appname: path = os.path.join(path, appauthor, appname) elif sys.platform == 'darwin': path = os.path.expanduser('/Library/Application Support') if appname: path = os.path.join(path, appname) else: # XDG default for $XDG_DATA_DIRS # only first, if multipath is False path = os.getenv('XDG_DATA_DIRS', os.pathsep.join(['/usr/local/share', '/usr/share'])) pathlist = [ os.path.expanduser(x.rstrip(os.sep)) for x in path.split(os.pathsep) ] if appname: if version: appname = os.path.join(appname, version) pathlist = [ os.sep.join([x, appname]) for x in pathlist ] if multipath: path = os.pathsep.join(pathlist) else: path = pathlist[0] return path if appname and version: path = os.path.join(path, version) return path def user_config_dir(appname=None, appauthor=None, version=None, roaming=False): r"""Return full path to the user-specific config dir for this application. "appname" is the name of application. If None, just the system directory is returned. "appauthor" (only required and used on Windows) is the name of the appauthor or distributing body for this application. Typically it is the owning company name. This falls back to appname. "version" is an optional version path element to append to the path. You might want to use this if you want multiple versions of your app to be able to run independently. If used, this would typically be ".". Only applied when appname is present. "roaming" (boolean, default False) can be set True to use the Windows roaming appdata directory. That means that for users on a Windows network setup for roaming profiles, this user data will be sync'd on login. See for a discussion of issues. Typical user data directories are: Mac OS X: same as user_data_dir Unix: ~/.config/ # or in $XDG_CONFIG_HOME, if defined Win *: same as user_data_dir For Unix, we follow the XDG spec and support $XDG_DATA_HOME. That means, by deafult "~/.local/share/". """ if sys.platform in [ "win32", "darwin" ]: path = user_data_dir(appname, appauthor, None, roaming) else: path = os.getenv('XDG_CONFIG_HOME', os.path.expanduser("~/.config")) if appname: path = os.path.join(path, appname) if appname and version: path = os.path.join(path, version) return path def site_config_dir(appname=None, appauthor=None, version=None, multipath=False): """Return full path to the user-shared data dir for this application. "appname" is the name of application. If None, just the system directory is returned. "appauthor" (only required and used on Windows) is the name of the appauthor or distributing body for this application. Typically it is the owning company name. This falls back to appname. "version" is an optional version path element to append to the path. You might want to use this if you want multiple versions of your app to be able to run independently. If used, this would typically be ".". Only applied when appname is present. "multipath" is an optional parameter only applicable to *nix which indicates that the entire list of config dirs should be returned. By default, the first item from XDG_CONFIG_DIRS is returned, or '/etc/xdg/', if XDG_CONFIG_DIRS is not set Typical user data directories are: Mac OS X: same as site_data_dir Unix: /etc/xdg/ or $XDG_CONFIG_DIRS[i]/ for each value in $XDG_CONFIG_DIRS Win *: same as site_data_dir Vista: (Fail! "C:\ProgramData" is a hidden *system* directory on Vista.) For Unix, this is using the $XDG_CONFIG_DIRS[0] default, if multipath=False WARNING: Do not use this on Windows. See the Vista-Fail note above for why. """ if sys.platform in [ "win32", "darwin" ]: path = site_data_dir(appname, appauthor) if appname and version: path = os.path.join(path, version) else: # XDG default for $XDG_CONFIG_DIRS # only first, if multipath is False path = os.getenv('XDG_CONFIG_DIRS', '/etc/xdg') pathlist = [ os.path.expanduser(x.rstrip(os.sep)) for x in path.split(os.pathsep) ] if appname: if version: appname = os.path.join(appname, version) pathlist = [ os.sep.join([x, appname]) for x in pathlist ] if multipath: path = os.pathsep.join(pathlist) else: path = pathlist[0] return path def user_cache_dir(appname=None, appauthor=None, version=None, opinion=True): r"""Return full path to the user-specific cache dir for this application. "appname" is the name of application. If None, just the system directory is returned. "appauthor" (only required and used on Windows) is the name of the appauthor or distributing body for this application. Typically it is the owning company name. This falls back to appname. "version" is an optional version path element to append to the path. You might want to use this if you want multiple versions of your app to be able to run independently. If used, this would typically be ".". Only applied when appname is present. "opinion" (boolean) can be False to disable the appending of "Cache" to the base app data dir for Windows. See discussion below. Typical user cache directories are: Mac OS X: ~/Library/Caches/ Unix: ~/.cache/ (XDG default) Win XP: C:\Documents and Settings\\Local Settings\Application Data\\\Cache Vista: C:\Users\\AppData\Local\\\Cache On Windows the only suggestion in the MSDN docs is that local settings go in the `CSIDL_LOCAL_APPDATA` directory. This is identical to the non-roaming app data dir (the default returned by `user_data_dir` above). Apps typically put cache data somewhere *under* the given dir here. Some examples: ...\Mozilla\Firefox\Profiles\\Cache ...\Acme\SuperApp\Cache\1.0 OPINION: This function appends "Cache" to the `CSIDL_LOCAL_APPDATA` value. This can be disabled with the `opinion=False` option. """ if sys.platform == "win32": if appauthor is None: appauthor = appname path = os.path.normpath(_get_win_folder("CSIDL_LOCAL_APPDATA")) if appname: path = os.path.join(path, appauthor, appname) if opinion: path = os.path.join(path, "Cache") elif sys.platform == 'darwin': path = os.path.expanduser('~/Library/Caches') if appname: path = os.path.join(path, appname) else: path = os.getenv('XDG_CACHE_HOME', os.path.expanduser('~/.cache')) if appname: path = os.path.join(path, appname) if appname and version: path = os.path.join(path, version) return path def user_log_dir(appname=None, appauthor=None, version=None, opinion=True): r"""Return full path to the user-specific log dir for this application. "appname" is the name of application. If None, just the system directory is returned. "appauthor" (only required and used on Windows) is the name of the appauthor or distributing body for this application. Typically it is the owning company name. This falls back to appname. "version" is an optional version path element to append to the path. You might want to use this if you want multiple versions of your app to be able to run independently. If used, this would typically be ".". Only applied when appname is present. "opinion" (boolean) can be False to disable the appending of "Logs" to the base app data dir for Windows, and "log" to the base cache dir for Unix. See discussion below. Typical user cache directories are: Mac OS X: ~/Library/Logs/ Unix: ~/.cache//log # or under $XDG_CACHE_HOME if defined Win XP: C:\Documents and Settings\\Local Settings\Application Data\\\Logs Vista: C:\Users\\AppData\Local\\\Logs On Windows the only suggestion in the MSDN docs is that local settings go in the `CSIDL_LOCAL_APPDATA` directory. (Note: I'm interested in examples of what some windows apps use for a logs dir.) OPINION: This function appends "Logs" to the `CSIDL_LOCAL_APPDATA` value for Windows and appends "log" to the user cache dir for Unix. This can be disabled with the `opinion=False` option. """ if sys.platform == "darwin": path = os.path.join( os.path.expanduser('~/Library/Logs'), appname) elif sys.platform == "win32": path = user_data_dir(appname, appauthor, version); version=False if opinion: path = os.path.join(path, "Logs") else: path = user_cache_dir(appname, appauthor, version); version=False if opinion: path = os.path.join(path, "log") if appname and version: path = os.path.join(path, version) return path class AppDirs(object): """Convenience wrapper for getting application dirs.""" def __init__(self, appname, appauthor=None, version=None, roaming=False, multipath=False): self.appname = appname self.appauthor = appauthor self.version = version self.roaming = roaming self.multipath = multipath @property def user_data_dir(self): return user_data_dir(self.appname, self.appauthor, version=self.version, roaming=self.roaming) @property def site_data_dir(self): return site_data_dir(self.appname, self.appauthor, version=self.version, multipath=self.multipath) @property def user_config_dir(self): return user_config_dir(self.appname, self.appauthor, version=self.version, roaming=self.roaming) @property def site_config_dir(self): return site_data_dir(self.appname, self.appauthor, version=self.version, multipath=self.multipath) @property def user_cache_dir(self): return user_cache_dir(self.appname, self.appauthor, version=self.version) @property def user_log_dir(self): return user_log_dir(self.appname, self.appauthor, version=self.version) #---- internal support stuff def _get_win_folder_from_registry(csidl_name): """This is a fallback technique at best. I'm not sure if using the registry for this guarantees us the correct answer for all CSIDL_* names. """ import _winreg shell_folder_name = { "CSIDL_APPDATA": "AppData", "CSIDL_COMMON_APPDATA": "Common AppData", "CSIDL_LOCAL_APPDATA": "Local AppData", }[csidl_name] key = _winreg.OpenKey(_winreg.HKEY_CURRENT_USER, r"Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders") dir, type = _winreg.QueryValueEx(key, shell_folder_name) return dir def _get_win_folder_with_pywin32(csidl_name): from win32com.shell import shellcon, shell dir = shell.SHGetFolderPath(0, getattr(shellcon, csidl_name), 0, 0) # Try to make this a unicode path because SHGetFolderPath does # not return unicode strings when there is unicode data in the # path. try: dir = unicode(dir) # Downgrade to short path name if have highbit chars. See # . has_high_char = False for c in dir: if ord(c) > 255: has_high_char = True break if has_high_char: try: import win32api dir = win32api.GetShortPathName(dir) except ImportError: pass except UnicodeError: pass return dir def _get_win_folder_with_ctypes(csidl_name): import ctypes csidl_const = { "CSIDL_APPDATA": 26, "CSIDL_COMMON_APPDATA": 35, "CSIDL_LOCAL_APPDATA": 28, }[csidl_name] buf = ctypes.create_unicode_buffer(1024) ctypes.windll.shell32.SHGetFolderPathW(None, csidl_const, None, 0, buf) # Downgrade to short path name if have highbit chars. See # . has_high_char = False for c in buf: if ord(c) > 255: has_high_char = True break if has_high_char: buf2 = ctypes.create_unicode_buffer(1024) if ctypes.windll.kernel32.GetShortPathNameW(buf.value, buf2, 1024): buf = buf2 return buf.value if sys.platform == "win32": try: import win32com.shell _get_win_folder = _get_win_folder_with_pywin32 except ImportError: try: import ctypes _get_win_folder = _get_win_folder_with_ctypes except ImportError: _get_win_folder = _get_win_folder_from_registry #---- self test code if __name__ == "__main__": appname = "MyApp" appauthor = "MyCompany" props = ("user_data_dir", "site_data_dir", "user_config_dir", "site_config_dir", "user_cache_dir", "user_log_dir") print("-- app dirs (with optional 'version')") dirs = AppDirs(appname, appauthor, version="1.0") for prop in props: print("%s: %s" % (prop, getattr(dirs, prop))) print("\n-- app dirs (without optional 'version')") dirs = AppDirs(appname, appauthor) for prop in props: print("%s: %s" % (prop, getattr(dirs, prop))) print("\n-- app dirs (without optional 'appauthor')") dirs = AppDirs(appname) for prop in props: print("%s: %s" % (prop, getattr(dirs, prop))) rosdistro-0.8.0/src/rosdistro/freeze_source.py000066400000000000000000000120271357352161700216140ustar00rootroot00000000000000# Software License Agreement (BSD License) # # Copyright (c) 2016, Clearpath Robotics # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # * Redistributions in binary form must reproduce the above # copyright notice, this list of conditions and the following # disclaimer in the documentation and/or other materials provided # with the distribution. # * Neither the name of Open Source Robotics Foundation, Inc. nor # the names of its contributors may be used to endorse or promote # products derived from this software without specific prior # written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. from __future__ import print_function import subprocess import sys import threading import time try: import queue except ImportError: import Queue as queue CONCURRENT_DEFAULT = 16 def freeze_distribution_sources(dist, release_version=False, release_tag=False, concurrent_ops=CONCURRENT_DEFAULT, quiet=False): # Populate this queue with tuples of repositories instances to be updated, # so that this work can be spread across multiple threads. work_queue = queue.Queue() for repo_name, repo in dist.repositories.items(): # Only manipulate distribution entries with a source repo listed. if repo.source_repository: # Decide which git ref string we'll be using as the replacement match. if repo.release_repository and (release_version or release_tag): version = repo.release_repository.version.split('-')[0] else: version = repo.source_repository.version work_queue.put((repo.source_repository, version, release_tag)) total_items = work_queue.qsize() for i in range(concurrent_ops): threading.Thread(target=_worker, args=[work_queue]).start() # Wait until the threads have done all the work and exited. while not work_queue.empty(): time.sleep(0.1) if not quiet: sys.stdout.write("Updating source repo versions (%d/%d) \r" % (total_items - work_queue.qsize(), total_items)) sys.stdout.flush() work_queue.join() # Clear past the updating line. if not quiet: print("") # Get the repo commit information def _get_repo_info(url, retry=2, retry_period=1): cmd = ['git', 'ls-remote', url] try: return subprocess.check_output(cmd).decode().splitlines() except subprocess.CalledProcessError as err: if not retry: raise print(' Non-zero return code for: %s, retrying in %f seconds' % (' '.join(cmd), retry_period), file=sys.stderr) # brief delay incase its an intermittent issue with infrastructure time.sleep(retry_period) return _get_repo_info(url, retry=retry - 1, retry_period=retry_period * 2) def _worker(work_queue): while True: try: source_repo, freeze_version, freeze_to_tag = work_queue.get(block=False) ls_remote_lines = _get_repo_info(source_repo.url) for line in ls_remote_lines: hash, ref = line.split('\t', 1) if freeze_to_tag and ref == 'refs/tags/%s' % freeze_version: source_repo.version = ref.split('refs/tags/')[1] break elif ref in ('refs/heads/%s' % freeze_version, 'refs/tags/%s' % freeze_version): source_repo.version = hash break if not isinstance(source_repo.version, str): # On Python 2, explicitly encode back to string. Unnecessary on Python 3, because # we're already a unicode string since subprocess.check_output returned a bytes. source_repo.version = source_repo.version.encode() work_queue.task_done() except subprocess.CalledProcessError as e: print("No information could be retrieved for repo %s with error: %s" % (source_repo.url, e), file=sys.stderr) work_queue.task_done() except queue.Empty: break rosdistro-0.8.0/src/rosdistro/index.py000066400000000000000000000145001357352161700200610ustar00rootroot00000000000000# Software License Agreement (BSD License) # # Copyright (c) 2013, Open Source Robotics Foundation, Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # * Redistributions in binary form must reproduce the above # copyright notice, this list of conditions and the following # disclaimer in the documentation and/or other materials provided # with the distribution. # * Neither the name of Open Source Robotics Foundation, Inc. nor # the names of its contributors may be used to endorse or promote # products derived from this software without specific prior # written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. try: from urllib.parse import urlparse except ImportError: from urlparse import urlparse class Index(object): _type = 'index' def __init__(self, data, base_url, url_query=''): assert 'type' in data, "Expected file type is '%s'" % Index._type assert data['type'] == Index._type, "Expected file type is '%s', not '%s'" % (Index._type, data['type']) assert 'version' in data, 'Index file lacks required version information' assert int(data['version']) > 1, "Unable to handle '%s' format version '%d' anymore, please update your '%s' file to version '2', '3', or '4'" % (Index._type, int(data['version']), Index._type) assert int(data['version']) in [2, 3, 4], "Unable to handle '%s' format version '%d', please update rosdistro (e.g. on Ubuntu/Debian use: sudo apt-get update && sudo apt-get install --only-upgrade python-rosdistro)" % (Index._type, int(data['version'])) self.version = int(data['version']) self.distributions = {} if 'distributions' in data and data['distributions']: # if distributions is not a dict raise an exception including the value # this can be used to notify users (e.g. if an index.yaml file has been deleted / moved) if not isinstance(data['distributions'], dict): raise RuntimeError("Distributions type is invalid: expected 'dict', but got '%s': %s" % (type(data['distributions']).__name__, data['distributions'])) for distro_name in sorted(data['distributions']): self.distributions[distro_name] = {} distro_data = data['distributions'][distro_name] for key in distro_data: if key in ('distribution_status', 'distribution_type', 'python_version'): assert self.version >= 4, "'%s' format version '%d' does not allow a '%s' entry" % (Index._type, self.version, key) if key == 'python_version': assert isinstance(distro_data[key], int), 'wrong type of key "%s"' % key else: assert isinstance(distro_data[key], str), 'wrong type of key "%s"' % key self.distributions[distro_name][key] = distro_data[key] continue if key in ['distribution']: if self.version == 2: list_value = False elif self.version in (3, 4): list_value = True else: assert False elif key in ['distribution_cache']: list_value = False elif key in ['release_builds', 'source_builds', 'doc_builds']: if self.version == 2: list_value = True elif self.version in (3, 4): assert False, "'%s' format version '%d' does not allow a '%s' entry anymore" % (Index._type, self.version, key) else: assert False else: if self.version <= 3: assert False, 'unknown key "%s"' % key # ignoring unknown keys # in order to allow adding new ones in the future # without the need to level the version continue self.distributions[distro_name][key] = [] value = distro_data[key] if list_value != isinstance(value, list): assert False, 'wrong type of key "%s"' % key if not list_value: value = [value] for v in value: parts = urlparse(v) if not parts[0]: # schema v = base_url + '/' + v if url_query: v += '?' + url_query self.distributions[distro_name][key].append(v) if not list_value: self.distributions[distro_name][key] = self.distributions[distro_name][key][0] # for backward compatibility only if key == 'distribution': self.distributions[distro_name]['release'] = self.distributions[distro_name][key] # for backward compatibility only for key in ['release_builds', 'source_builds', 'doc_builds']: if key not in self.distributions[distro_name]: self.distributions[distro_name][key] = [] rosdistro-0.8.0/src/rosdistro/legacy.py000066400000000000000000000207771357352161700202330ustar00rootroot00000000000000# Software License Agreement (BSD License) # # Copyright (c) 2013, Open Source Robotics Foundation, Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # * Redistributions in binary form must reproduce the above # copyright notice, this list of conditions and the following # disclaimer in the documentation and/or other materials provided # with the distribution. # * Neither the name of Open Source Robotics Foundation, Inc. nor # the names of its contributors may be used to endorse or promote # products derived from this software without specific prior # written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. from __future__ import print_function import gzip try: from cStringIO import StringIO except ImportError: from io import BytesIO as StringIO import sys import yaml from . import _get_dist_file_data from . import logger # legacy imports from . import common # noqa from .aptdistro import AptDistro # noqa from .develdistro import DevelDistro # noqa from .rosdistro import RosDistro # noqa from .rosdistro import walks # noqa from .doc_build_file import DocBuildFile from .doc_file import DocFile from .loader import load_url from .manifest_provider.cache import CachedManifestProvider from .release import Release from .release_build import ReleaseBuild from .release_build_file import ReleaseBuildFile from .release_cache import ReleaseCache from .release_file import ReleaseFile from .source_build_file import SourceBuildFile from .source_file import SourceFile # release information def get_cached_release(index, dist_name, cache=None, allow_lazy_load=False): print('# rosdistro.get_cached_release() has been deprecated in favor of the new function rosdistro.get_cached_distribution() - please check that you have the latest versions of the Python tools (e.g. on Ubuntu/Debian use: sudo apt-get update && sudo apt-get install --only-upgrade python-bloom python-rosdep python-rosinstall python-rosinstall-generator)', file=sys.stderr) if cache is None: try: cache = get_release_cache(index, dist_name) except Exception: if not allow_lazy_load: raise # create empty cache instance rel_file_data = _get_dist_file_data(index, dist_name, 'release') cache = ReleaseCache(dist_name, rel_file_data=rel_file_data) rel = Release( cache.release_file, [CachedManifestProvider(cache, Release.default_manifest_providers if allow_lazy_load else None)]) assert cache.release_file.name == dist_name return rel def get_release(index, dist_name): print('# rosdistro.get_release() has been deprecated in favor of the new function rosdistro.get_cached_distribution() - please check that you have the latest versions of the Python tools (e.g. on Ubuntu/Debian use: sudo apt-get update && sudo apt-get install --only-upgrade python-bloom python-rosdep python-rosinstall python-rosinstall-generator)', file=sys.stderr) rel_file = get_release_file(index, dist_name) return Release(rel_file) def get_release_file(index, dist_name): print('# rosdistro.get_release_file() has been deprecated in favor of the new function rosdistro.get_distribution_file() - please check that you have the latest versions of the Python tools (e.g. on Ubuntu/Debian use: sudo apt-get update && sudo apt-get install --only-upgrade python-bloom python-rosdep python-rosinstall python-rosinstall-generator)', file=sys.stderr) data = _get_dist_file_data(index, dist_name, 'distribution') return ReleaseFile(dist_name, data) def get_release_cache(index, dist_name): print('# rosdistro.get_release_cache() has been deprecated in favor of the new function rosdistro.get_distribution_cache() - please check that you have the latest versions of the Python tools (e.g. on Ubuntu/Debian use: sudo apt-get update && sudo apt-get install --only-upgrade python-bloom python-rosdep python-rosinstall python-rosinstall-generator)', file=sys.stderr) if dist_name not in index.distributions.keys(): raise RuntimeError("Unknown release: '{0}'. Valid release names are: {1}".format(dist_name, ', '.join(sorted(index.distributions.keys())))) dist = index.distributions[dist_name] if 'distribution_cache' not in dist.keys(): raise RuntimeError("Release has no cache: '{0}'".format(dist_name)) url = dist['distribution_cache'] logger.debug('Load cache from "%s"' % url) if url.endswith('.yaml'): yaml_str = load_url(url) elif url.endswith('.yaml.gz'): yaml_gz_str = load_url(url, skip_decode=True) yaml_gz_stream = StringIO(yaml_gz_str) f = gzip.GzipFile(fileobj=yaml_gz_stream, mode='rb') yaml_str = f.read() if not isinstance(yaml_str, str): yaml_str = yaml_str.decode('utf-8') f.close() else: raise NotImplementedError('The url of the cache must end with either ".yaml" or ".yaml.gz"') data = yaml.load(yaml_str) return ReleaseCache(dist_name, data) def get_release_builds(index, release_file): print("# rosdistro.get_release_builds() has been deprecated and its functionality is now handled by the 'ros_buildfarm.config' module", file=sys.stderr) build_files = get_release_build_files(index, release_file.name) builds = [] for build_file in build_files: builds.append(ReleaseBuild(release_file, build_file)) return builds def get_release_build_files(index, dist_name): print("# rosdistro.get_release_build_files() has been deprecated and its functionality is now handled by the 'ros_buildfarm.config' module", file=sys.stderr) data = _get_dist_file_data(index, dist_name, 'release_builds') build_files = [] for d in data: build_files.append(ReleaseBuildFile(dist_name, d)) return build_files # source information def get_source_file(index, dist_name): print('# rosdistro.get_source_file() has been deprecated in favor of the new function rosdistro.get_distribution_file() - please check that you have the latest versions of the Python tools (e.g. on Ubuntu/Debian use: sudo apt-get update && sudo apt-get install --only-upgrade python-bloom python-rosdep python-rosinstall python-rosinstall-generator)', file=sys.stderr) data = _get_dist_file_data(index, dist_name, 'distribution') return SourceFile(dist_name, data) def get_source_build_files(index, dist_name): print("# rosdistro.get_source_build_files() has been deprecated and its functionality is now handled by the 'ros_buildfarm.config' module", file=sys.stderr) data = _get_dist_file_data(index, dist_name, 'source_builds') build_files = [] for d in data: build_files.append(SourceBuildFile(dist_name, d)) return build_files # doc information def get_doc_file(index, dist_name): print('# rosdistro.get_doc_file() has been deprecated in favor of the new function rosdistro.get_distribution_file() - please check that you have the latest versions of the Python tools (e.g. on Ubuntu/Debian use: sudo apt-get update && sudo apt-get install --only-upgrade python-bloom python-rosdep python-rosinstall python-rosinstall-generator)', file=sys.stderr) data = _get_dist_file_data(index, dist_name, 'distribution') return DocFile(dist_name, data) def get_doc_build_files(index, dist_name): print("# rosdistro.get_doc_build_files() has been deprecated and its functionality is now handled by the 'ros_buildfarm.config' module", file=sys.stderr) data = _get_dist_file_data(index, dist_name, 'doc_builds') build_files = [] for d in data: build_files.append(DocBuildFile(dist_name, d)) return build_files rosdistro-0.8.0/src/rosdistro/loader.py000066400000000000000000000054031357352161700202220ustar00rootroot00000000000000# Software License Agreement (BSD License) # # Copyright (c) 2013, Open Source Robotics Foundation, Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # * Redistributions in binary form must reproduce the above # copyright notice, this list of conditions and the following # disclaimer in the documentation and/or other materials provided # with the distribution. # * Neither the name of Open Source Robotics Foundation, Inc. nor # the names of its contributors may be used to endorse or promote # products derived from this software without specific prior # written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. import socket import time try: from urllib.request import urlopen from urllib.error import HTTPError from urllib.error import URLError except ImportError: from urllib2 import urlopen from urllib2 import HTTPError from urllib2 import URLError def load_url(url, retry=2, retry_period=1, timeout=10, skip_decode=False): try: fh = urlopen(url, timeout=timeout) except HTTPError as e: if e.code in [500, 502, 503] and retry: time.sleep(retry_period) return load_url(url, retry=retry - 1, retry_period=retry_period, timeout=timeout) e.msg += ' (%s)' % url raise except URLError as e: if isinstance(e.reason, socket.timeout) and retry: time.sleep(retry_period) return load_url(url, retry=retry - 1, retry_period=retry_period, timeout=timeout) raise URLError(str(e) + ' (%s)' % url) except socket.timeout as e: raise socket.timeout(str(e) + ' (%s)' % url) # Python 2/3 Compatibility contents = fh.read() if isinstance(contents, str) or skip_decode: return contents else: return contents.decode('utf-8') rosdistro-0.8.0/src/rosdistro/manifest_provider/000077500000000000000000000000001357352161700221205ustar00rootroot00000000000000rosdistro-0.8.0/src/rosdistro/manifest_provider/__init__.py000066400000000000000000000035221357352161700242330ustar00rootroot00000000000000# Software License Agreement (BSD License) # # Copyright (c) 2013, Open Source Robotics Foundation, Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # * Redistributions in binary form must reproduce the above # copyright notice, this list of conditions and the following # disclaimer in the documentation and/or other materials provided # with the distribution. # * Neither the name of Open Source Robotics Foundation, Inc. nor # the names of its contributors may be used to endorse or promote # products derived from this software without specific prior # written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. # This function remains here as a compatibility shim because there is code # in older rosinstall_generator versions which uses it in this location. def get_release_tag(repo, pkg_name): return repo.get_release_tag(pkg_name) rosdistro-0.8.0/src/rosdistro/manifest_provider/bitbucket.py000066400000000000000000000066421357352161700244560ustar00rootroot00000000000000# Software License Agreement (BSD License) # # Copyright (c) 2016, Clearpath Robotics # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # * Redistributions in binary form must reproduce the above # copyright notice, this list of conditions and the following # disclaimer in the documentation and/or other materials provided # with the distribution. # * Neither the name of Open Source Robotics Foundation, Inc. nor # the names of its contributors may be used to endorse or promote # products derived from this software without specific prior # written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. try: from urllib.request import urlopen, Request from urllib.error import URLError except ImportError: from urllib2 import urlopen, Request from urllib2 import URLError import base64 import os from rosdistro import logger # This Bitbucket provider can optionally send basic auth to fetch from # private repositories if you supply the environment variables # BITBUCKET_USER and BITBUCKET_PASSWORD. This can be the credentials # for an actual Bitbucket user, or it can be a team name with API key. # # Generate an API key for your team here: # https://bitbucket.org/account/user//api-key/ BITBUCKET_USER = os.getenv('BITBUCKET_USER', None) BITBUCKET_PASSWORD = os.getenv('BITBUCKET_PASSWORD', None) def bitbucket_manifest_provider(_dist_name, repo, pkg_name): assert repo.version server, path = repo.get_url_parts() if not server.endswith('bitbucket.org'): logger.debug('Skip non-bitbucket url "%s"' % repo.url) raise RuntimeError('Cannot handle non bitbucket url.') release_tag = repo.get_release_tag(pkg_name) if not repo.has_remote_tag(release_tag): raise RuntimeError('specified tag "%s" is not a git tag' % release_tag) url = 'https://bitbucket.org/%s/raw/%s/package.xml' % (path, release_tag) try: logger.debug('Load package.xml file from url "%s"' % url) req = Request(url) if BITBUCKET_USER and BITBUCKET_PASSWORD: logger.debug('- using http basic auth from supplied environment variables.') authheader = 'Basic %s' % base64.b64encode('%s:%s' % (BITBUCKET_USER, BITBUCKET_PASSWORD)) req.add_header('Authorization', authheader) package_xml = urlopen(req).read().decode('utf-8') return package_xml except URLError as e: logger.debug('- failed (%s)' % e) raise RuntimeError() rosdistro-0.8.0/src/rosdistro/manifest_provider/cache.py000066400000000000000000000137401357352161700235420ustar00rootroot00000000000000# Software License Agreement (BSD License) # # Copyright (c) 2013, Open Source Robotics Foundation, Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # * Redistributions in binary form must reproduce the above # copyright notice, this list of conditions and the following # disclaimer in the documentation and/or other materials provided # with the distribution. # * Neither the name of Open Source Robotics Foundation, Inc. nor # the names of its contributors may be used to endorse or promote # products derived from this software without specific prior # written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. from xml.dom import minidom from rosdistro import logger def sanitize_xml(xml_string): """ Returns a version of the supplied XML string with comments and all whitespace stripped, including runs of spaces internal to text nodes. The returned string will be encoded, so str (Python 2) or bytes (Python 3). """ def _squash(node): # remove comment nodes for x in list(node.childNodes): if x.nodeType is minidom.Node.COMMENT_NODE: node.removeChild(x) # minimize whitespaces, remove empty text nodes for x in list(node.childNodes): if x.nodeType == minidom.Node.TEXT_NODE: if x.nodeValue: x.nodeValue = ' '.join(x.nodeValue.strip().split()) if not x.nodeValue: node.removeChild(x) # process all tags recusively for x in node.childNodes: if x.nodeType == minidom.Node.ELEMENT_NODE: _squash(x) return node try: # Python 2. The minidom module parses as ascii, so we have to pre-encode. if isinstance(xml_string, unicode): xml_string = xml_string.encode('utf-8') except NameError: # Python 3. Strings are native unicode. pass xml_node = _squash(minidom.parseString(xml_string)) try: # Python 2. Encode the resultant XML as a str. unicode return xml_node.toxml('utf-8') except NameError: # Python 3. Return native bytes. return xml_node.toxml() class CachedManifestProvider(object): def __init__(self, distribution_cache, manifest_providers=None): self._distribution_cache = distribution_cache self._manifest_providers = manifest_providers def __call__(self, dist_name, repo, pkg_name): assert repo.version package_xml = self._distribution_cache.release_package_xmls.get(pkg_name, None) if package_xml: package_xml = sanitize_xml(package_xml) self._distribution_cache.release_package_xmls[pkg_name] = package_xml logger.debug('Loading package.xml for package "%s" from cache' % pkg_name) else: # use manifest providers to lazy load for mp in self._manifest_providers or []: try: package_xml = sanitize_xml(mp(dist_name, repo, pkg_name)) break except Exception as e: # pass and try next manifest provider logger.debug('Skipped "%s()": %s' % (mp.__name__, e)) if package_xml is None: return None # populate the cache self._distribution_cache.release_package_xmls[pkg_name] = package_xml return package_xml class CachedSourceManifestProvider(object): def __init__(self, distribution_cache, source_manifest_providers=None): self._distribution_cache = distribution_cache self._source_manifest_providers = source_manifest_providers def __call__(self, repo): assert repo.url repo_cache = self._distribution_cache.source_repo_package_xmls.get(repo.name, None) if not repo_cache: # Use manifest providers to lazy load for mp in self._source_manifest_providers or []: try: repo_cache = mp(repo) except Exception as e: # pass and try next manifest provider logger.debug('Skipped "%s()": %s' % (mp.__name__, e)) continue self._distribution_cache.source_repo_package_xmls[repo.name] = repo_cache break else: logger.debug('Load package XMLs for repo "%s" from cache' % repo.name) # De-duplicate with the release package XMLs. This will cause the YAML writer # to use references for the common strings, saving a lot of space in the cache file. if repo_cache: for package_name, package_path, package_xml in repo_cache.items(): package_xml = sanitize_xml(package_xml) release_package_xml = self._distribution_cache.release_package_xmls.get(package_name, None) if package_xml == release_package_xml: package_xml = release_package_xml repo_cache.add(package_name, package_path, package_xml) return repo_cache rosdistro-0.8.0/src/rosdistro/manifest_provider/git.py000066400000000000000000000113471357352161700232630ustar00rootroot00000000000000# Software License Agreement (BSD License) # # Copyright (c) 2013, Open Source Robotics Foundation, Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # * Redistributions in binary form must reproduce the above # copyright notice, this list of conditions and the following # disclaimer in the documentation and/or other materials provided # with the distribution. # * Neither the name of Open Source Robotics Foundation, Inc. nor # the names of its contributors may be used to endorse or promote # products derived from this software without specific prior # written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. import os import shutil import tempfile from contextlib import contextmanager from catkin_pkg.package import InvalidPackage, parse_package_string from catkin_pkg.packages import find_package_paths from rosdistro.source_repository_cache import SourceRepositoryCache from rosdistro.vcs import Git, ref_is_hash def git_manifest_provider(_dist_name, repo, pkg_name): assert repo.version try: release_tag = repo.get_release_tag(pkg_name) with _temp_git_clone(repo.url, release_tag) as git_repo_path: filename = os.path.join(git_repo_path, 'package.xml') if not os.path.exists(filename): raise RuntimeError('Could not find package.xml in repository "%s"' % repo.url) with open(filename, 'r') as f: return f.read() except Exception as e: raise RuntimeError('Unable to fetch package.xml: %s' % e) def git_source_manifest_provider(repo): try: with _temp_git_clone(repo.url, repo.version) as git_repo_path: # Include the git hash in our cache dictionary. git_hash = Git(git_repo_path).command('rev-parse', 'HEAD')['output'] cache = SourceRepositoryCache.from_ref(git_hash) # Find package.xml files inside the repo. for package_path in find_package_paths(git_repo_path): if package_path == '.': package_path = '' with open(os.path.join(git_repo_path, package_path, 'package.xml'), 'r') as f: package_xml = f.read() try: name = parse_package_string(package_xml).name except InvalidPackage: raise RuntimeError('Unable to parse package.xml file found in %s' % repo.url) cache.add(name, package_path, package_xml) except Exception as e: raise RuntimeError('Unable to fetch source package.xml files: %s' % e) return cache @contextmanager def _temp_git_clone(url, ref): base = tempfile.mkdtemp('rosdistro') git = Git(cwd=base) try: if git.version_gte('1.8.0') and not ref_is_hash(ref): # Directly clone the required ref with least amount of additional history. # Available since git 1.8.0, but only works for tags and branches, not hashes: # https://git.kernel.org/cgit/git/git.git/tree/Documentation/git-clone.txt?h=v1.8.0#n158 result = git.command('clone', url, '.', '--depth', '1', '--branch', ref) if result['returncode'] != 0: raise RuntimeError('Could not clone repository "%s" at reference "%s"' % (url, ref)) else: # Old git doesn't support cloning a tag/branch directly, so full clone and checkout. result = git.command('clone', url, '.') if result['returncode'] != 0: raise RuntimeError('Could not clone repository "%s"' % url) result = git.command('checkout', ref) if result['returncode'] != 0: raise RuntimeError('Could not checkout ref "%s" of repository "%s"' % (ref, url)) yield base finally: shutil.rmtree(base) rosdistro-0.8.0/src/rosdistro/manifest_provider/github.py000066400000000000000000000117641357352161700237650ustar00rootroot00000000000000# Software License Agreement (BSD License) # # Copyright (c) 2013, Open Source Robotics Foundation, Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # * Redistributions in binary form must reproduce the above # copyright notice, this list of conditions and the following # disclaimer in the documentation and/or other materials provided # with the distribution. # * Neither the name of Open Source Robotics Foundation, Inc. nor # the names of its contributors may be used to endorse or promote # products derived from this software without specific prior # written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. try: from urllib.request import urlopen, Request from urllib.error import URLError except ImportError: from urllib2 import urlopen, Request from urllib2 import URLError import base64 import json import os from catkin_pkg.package import parse_package_string from rosdistro.source_repository_cache import SourceRepositoryCache from rosdistro import logger GITHUB_USER = os.getenv('GITHUB_USER', None) GITHUB_PASSWORD = os.getenv('GITHUB_PASSWORD', None) def _get_url_contents(url): return urlopen(url).read().decode('utf-8') def github_manifest_provider(_dist_name, repo, pkg_name): assert repo.version server, path = repo.get_url_parts() if not server.endswith('github.com'): logger.debug('Skip non-github url "%s"' % repo.url) raise RuntimeError('can not handle non github urls') release_tag = repo.get_release_tag(pkg_name) if not repo.has_remote_tag(release_tag): raise RuntimeError('specified tag "%s" is not a git tag' % release_tag) url = 'https://raw.githubusercontent.com/%s/%s/package.xml' % (path, release_tag) try: logger.debug('Load package.xml file from url "%s"' % url) return _get_url_contents(url) except URLError as e: logger.debug('- failed (%s), trying "%s"' % (e, url)) raise RuntimeError() def github_source_manifest_provider(repo): server, path = repo.get_url_parts() if not server.endswith('github.com'): logger.debug('Skip non-github url "%s"' % repo.url) raise RuntimeError('can not handle non github urls') tree_url = 'https://api.github.com/repos/%s/git/trees/%s?recursive=1' % (path, repo.version) req = Request(tree_url) if GITHUB_USER and GITHUB_PASSWORD: logger.debug('- using http basic auth from supplied environment variables.') authheader = 'Basic %s' % base64.b64encode('%s:%s' % (GITHUB_USER, GITHUB_PASSWORD)) req.add_header('Authorization', authheader) try: tree_json = json.loads(_get_url_contents(req)) logger.debug('- load repo tree from %s' % tree_url) except URLError as e: raise RuntimeError('Unable to fetch JSON tree from %s: %s' % (tree_url, e)) if tree_json['truncated']: raise RuntimeError('JSON tree is truncated, must perform full clone.') package_xml_paths = set() for obj in tree_json['tree']: if obj['path'].split('/')[-1] == 'package.xml': package_xml_paths.add(os.path.dirname(obj['path'])) # Filter out ones that are inside other packages (eg, part of tests) def package_xml_in_parent(path): if path == '': return True parent = path while True: parent = os.path.dirname(parent) if parent in package_xml_paths: return False if parent == '': return True package_xml_paths = list(filter(package_xml_in_parent, package_xml_paths)) cache = SourceRepositoryCache.from_ref(tree_json['sha']) for package_xml_path in package_xml_paths: url = 'https://raw.githubusercontent.com/%s/%s/%s' % \ (path, cache.ref(), package_xml_path + '/package.xml' if package_xml_path else 'package.xml') logger.debug('- load package.xml from %s' % url) package_xml = _get_url_contents(url) name = parse_package_string(package_xml).name cache.add(name, package_xml_path, package_xml) return cache rosdistro-0.8.0/src/rosdistro/package.py000066400000000000000000000036011357352161700203450ustar00rootroot00000000000000# Software License Agreement (BSD License) # # Copyright (c) 2013, Open Source Robotics Foundation, Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # * Redistributions in binary form must reproduce the above # copyright notice, this list of conditions and the following # disclaimer in the documentation and/or other materials provided # with the distribution. # * Neither the name of Open Source Robotics Foundation, Inc. nor # the names of its contributors may be used to endorse or promote # products derived from this software without specific prior # written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. class Package: def __init__(self, name, repository_name): self.name = name self.repository_name = repository_name # for backward compatibility only self.subfolder = None self.status = None self.status_description = None rosdistro-0.8.0/src/rosdistro/release.py000066400000000000000000000064611357352161700204010ustar00rootroot00000000000000# Software License Agreement (BSD License) # # Copyright (c) 2013, Open Source Robotics Foundation, Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # * Redistributions in binary form must reproduce the above # copyright notice, this list of conditions and the following # disclaimer in the documentation and/or other materials provided # with the distribution. # * Neither the name of Open Source Robotics Foundation, Inc. nor # the names of its contributors may be used to endorse or promote # products derived from this software without specific prior # written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. from .manifest_provider.bitbucket import bitbucket_manifest_provider from .manifest_provider.git import git_manifest_provider from .manifest_provider.github import github_manifest_provider class Release(object): default_manifest_providers = [github_manifest_provider, bitbucket_manifest_provider, git_manifest_provider] def __init__(self, rel_file, manifest_providers=None): self._rel_file = rel_file # Use default self._manifest_providers = Release.default_manifest_providers # Override default if given if manifest_providers is not None: self._manifest_providers = manifest_providers self._package_xmls = {} def __getattr__(self, name): # for backward compatibility only if name == 'get_release_package_xml': return self.get_package_xml if name == 'release_packages': name = 'packages' if name == 'release_platforms': name = 'platforms' return getattr(self._rel_file, name) def get_package_xml(self, pkg_name): if pkg_name not in self._package_xmls: pkg = self._rel_file.packages[pkg_name] repo_name = pkg.repository_name repo = self._rel_file.repositories[repo_name] if repo.version is None: return None package_xml = None for mp in self._manifest_providers: # try: package_xml = mp(self._rel_file.name, repo, pkg_name) # except: # pass if package_xml is not None: break self._package_xmls[pkg_name] = package_xml return self._package_xmls[pkg_name] rosdistro-0.8.0/src/rosdistro/release_build.py000066400000000000000000000061751357352161700215620ustar00rootroot00000000000000# Software License Agreement (BSD License) # # Copyright (c) 2013, Open Source Robotics Foundation, Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # * Redistributions in binary form must reproduce the above # copyright notice, this list of conditions and the following # disclaimer in the documentation and/or other materials provided # with the distribution. # * Neither the name of Open Source Robotics Foundation, Inc. nor # the names of its contributors may be used to endorse or promote # products derived from this software without specific prior # written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. class ReleaseBuild(object): def __init__(self, dist, release_build_file): self._dist = dist self._build_file = release_build_file self._verify_package_names(self._build_file.package_whitelist) self._verify_package_names(self._build_file.package_blacklist) for os_name in self._build_file.get_target_os_names(): assert os_name in self._dist.platforms.keys(), "Distribution '%s' specifies to build for os_name '%s' which is not listed in the release file" % (self._dist.name, os_name) for os_code_name in self._build_file.get_target_os_code_names(os_name): assert os_code_name in self._dist.platforms[os_name], "Distribution '%s' specifies to build for os_code_name '%s' which is not listed in the release file" % (self._dist.name, os_code_name) self._verify_package_names(self._build_file.sync_packages) def _verify_package_names(self, pkg_names): if pkg_names: for pkg_name in pkg_names: assert pkg_name in self._dist.packages, "Distribution '%s' specifies to build the package '%s' which is not listed in the release file" % (self._dist.name, pkg_name) def __getattr__(self, name): return getattr(self._build_file, name) def get_package_names(self): if not self._build_file.package_whitelist and not self._build_file.package_blacklist: return self._dist.get_package_names() raise NotImplementedError('Package whitelisting/blacklisting has not been implemented yet') rosdistro-0.8.0/src/rosdistro/release_build_file.py000066400000000000000000000172621357352161700225600ustar00rootroot00000000000000# Software License Agreement (BSD License) # # Copyright (c) 2013, Open Source Robotics Foundation, Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # * Redistributions in binary form must reproduce the above # copyright notice, this list of conditions and the following # disclaimer in the documentation and/or other materials provided # with the distribution. # * Neither the name of Open Source Robotics Foundation, Inc. nor # the names of its contributors may be used to endorse or promote # products derived from this software without specific prior # written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. class ReleaseBuildFile(object): _type = 'release-build' def __init__(self, name, data): self.name = name assert 'type' in data, "Expected file type is '%s'" % ReleaseBuildFile._type assert data['type'] == ReleaseBuildFile._type, "Expected file type is '%s', not '%s'" % (ReleaseBuildFile._type, data['type']) assert 'version' in data, "Release build file for '%s' lacks required version information" % self.name assert int(data['version']) == 1, "Unable to handle '%s' format version '%d', please update rosdistro (e.g. on Ubuntu/Debian use: sudo apt-get update && sudo apt-get install --only-upgrade python-rosdistro)" % (ReleaseBuildFile._type, int(data['version'])) self.version = int(data['version']) self.package_whitelist = [] if 'package_whitelist' in data: self.package_whitelist = data['package_whitelist'] assert isinstance(self.package_whitelist, list) self.package_blacklist = [] if 'package_blacklist' in data: self.package_blacklist = data['package_blacklist'] assert isinstance(self.package_blacklist, list) self.notify_emails = [] self.notify_maintainers = None self.notify_committers = None if 'notifications' in data: if 'emails' in data['notifications']: self.notify_emails = data['notifications']['emails'] assert isinstance(self.notify_emails, list) if 'maintainers' in data['notifications'] and data['notifications']['maintainers']: self.notify_maintainers = True if 'committers' in data['notifications'] and data['notifications']['committers']: self.notify_committers = True assert 'targets' in data self._targets = {} for os_name in data['targets'].keys(): if os_name == '_config': self._targets[os_name] = data['targets'][os_name] continue self._targets[os_name] = {} for os_code_name in data['targets'][os_name]: if os_code_name == '_config': self._targets[os_name][os_code_name] = data['targets'][os_name][os_code_name] continue self._targets[os_name][os_code_name] = {} for arch in data['targets'][os_name][os_code_name]: self._targets[os_name][os_code_name][arch] = data['targets'][os_name][os_code_name][arch] assert 'jenkins_url' in data self.jenkins_url = str(data['jenkins_url']) self.jenkins_sourcedeb_job_timeout = None if 'jenkins_sourcedeb_job_timeout' in data: self.jenkins_sourcedeb_job_timeout = int(data['jenkins_sourcedeb_job_timeout']) self.jenkins_binarydeb_job_timeout = None if 'jenkins_binarydeb_job_timeout' in data: self.jenkins_binarydeb_job_timeout = int(data['jenkins_binarydeb_job_timeout']) self.sync_package_count = None self.sync_packages = [] if 'sync' in data: if 'package_count' in data['sync']: self.sync_package_count = int(data['sync']['package_count']) if 'packages' in data['sync']: self.notify_maintainers = data['sync']['packages'] assert isinstance(self.sync_packages, list) def get_target_os_names(self): return [t for t in self._targets.keys() if t != '_config'] def get_target_os_code_names(self, os_name): os_code_names = self._targets[os_name] return [t for t in os_code_names.keys() if t != '_config'] def get_target_arches(self, os_name, os_code_name): arches = self._targets[os_name][os_code_name] return [t for t in arches.keys() if t != '_config'] def get_target_configuration(self, os_name=None, os_code_name=None, arch=None): assert os_code_name is not None or arch is None assert os_name is not None or os_code_name is None config = {} if '_config' in self._targets: config.update(self._targets['_config']) if os_name is not None: if '_config' in self._targets[os_name]: config.update(self._targets[os_name]['_config']) if os_code_name is not None: if '_config' in self._targets[os_name][os_code_name]: config.update(self._targets[os_name][os_code_name]['_config']) if arch is not None: if '_config' in self._targets[os_name][os_code_name][arch]: config.update(self._targets[os_name][os_code_name][arch]['_config']) return config def get_data(self): data = {} data['type'] = ReleaseBuildFile._type data['version'] = 1 if self.package_whitelist: data['package_whitelist'] = self.package_whitelist if self.package_blacklist: data['package_blacklist'] = self.package_blacklist if self.notify_emails or self.notify_maintainers or self.notify_committers: data['notifications'] = {} if self.notify_emails: data['notifications']['emails'] = self.notify_emails if self.notify_maintainers is not None: data['notifications']['maintainers'] = bool(self.notify_maintainers) if self.notify_committers is not None: data['notifications']['committers'] = bool(self.notify_committers) data['targets'] = self._targets data['jenkins_url'] = self.jenkins_url if self.jenkins_sourcedeb_job_timeout: data['jenkins_sourcedeb_job_timeout'] = self.jenkins_sourcedeb_job_timeout if self.jenkins_binarydeb_job_timeout: data['jenkins_binarydeb_job_timeout'] = self.jenkins_binarydeb_job_timeout if self.sync_package_count or self.sync_packages: data['sync'] = {} if self.sync_package_count is not None: data['sync']['package_count'] = self.sync_package_count if self.sync_packages: data['sync']['packages'] = self.sync_packages return data rosdistro-0.8.0/src/rosdistro/release_cache.py000066400000000000000000000116321357352161700215200ustar00rootroot00000000000000# Software License Agreement (BSD License) # # Copyright (c) 2013, Open Source Robotics Foundation, Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # * Redistributions in binary form must reproduce the above # copyright notice, this list of conditions and the following # disclaimer in the documentation and/or other materials provided # with the distribution. # * Neither the name of Open Source Robotics Foundation, Inc. nor # the names of its contributors may be used to endorse or promote # products derived from this software without specific prior # written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. from __future__ import print_function from .release_file import ReleaseFile class ReleaseCache(object): _type = 'cache' def __init__(self, name, data=None, distribution_file_data=None): assert data or distribution_file_data if data: assert 'type' in data, "Expected file type is '%s'" % ReleaseCache._type assert data['type'] == ReleaseCache._type, "Expected file type is '%s', not '%s'" % (ReleaseCache._type, data['type']) assert 'version' in data, "Release cache file for '%s' lacks required version information" % name self.version = int(data['version']) assert self.version > 1, "Unable to handle '%s' format version '%d' anymore, please update your '%s' file to version '2'" % (ReleaseCache._type, self.version, ReleaseCache._type) assert self.version == 2, "Unable to handle '%s' format version '%d', please update rosdistro (e.g. on Ubuntu/Debian use: sudo apt-get update && sudo apt-get install --only-upgrade python-rosdistro)" % (ReleaseCache._type, self.version) assert 'name' in data, "Release cache file for '%s' lacks required name information" % name assert data['name'] == name, "Release cache file for '%s' does not match the name '%s'" % (name, data['name']) else: self.version = 2 self._distribution_file_data = data['distribution_file'] if data else distribution_file_data self.release_file = ReleaseFile(name, self._distribution_file_data) self.package_xmls = data['release_package_xmls'] if data else {} # for backward compatibility only def __getattr__(self, name): if name == 'release_package_xmls': return self.package_xmls raise AttributeError def get_data(self): data = {} data['type'] = 'cache' data['version'] = 2 data['name'] = self.release_file.name data['distribution_file'] = self._distribution_file_data data['package_xmls'] = self.package_xmls return data def update_distribution(self, distribution_file_data): # remove packages which are not in the old distribution file self._remove_obsolete_entries() self._distribution_file_data = distribution_file_data rel_file = ReleaseFile(self.distribution_file.name, self._distribution_file_data) # remove all package xmls if repository information has changed for pkg_name in sorted(rel_file.packages.keys()): if pkg_name not in self.release_file.packages: continue if pkg_name in self.package_xmls and self._get_repo_info(rel_file, pkg_name) != self._get_repo_info(self.release_file, pkg_name): del self.package_xmls[pkg_name] self.release_file = rel_file # remove packages which are not in the new distribution file self._remove_obsolete_entries() def _get_repo_info(self, dist_file, pkg_name): pkg = dist_file.packages[pkg_name] repo = dist_file.repositories[pkg.repository_name] return (repo.version, repo.url) def _remove_obsolete_entries(self): for pkg_name in self.package_xmls.keys(): if pkg_name not in self.release_file.packages: print('- REMOVE', pkg_name) del self.package_xmls[pkg_name] rosdistro-0.8.0/src/rosdistro/release_cache_generator.py000066400000000000000000000137471357352161700235770ustar00rootroot00000000000000# Software License Agreement (BSD License) # # Copyright (c) 2013, Open Source Robotics Foundation, Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # * Redistributions in binary form must reproduce the above # copyright notice, this list of conditions and the following # disclaimer in the documentation and/or other materials provided # with the distribution. # * Neither the name of Open Source Robotics Foundation, Inc. nor # the names of its contributors may be used to endorse or promote # products derived from this software without specific prior # written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. from __future__ import print_function import gzip import os import re import sys from catkin_pkg.package import InvalidPackage, parse_package_string import yaml from . import _get_dist_file_data, get_cached_release, get_index, get_release_cache from .release_cache import ReleaseCache def generate_release_caches(index, dist_names=None, preclean=False, debug=False): if os.path.isfile(index): index = 'file://' + os.path.abspath(index) index = get_index(index) if not dist_names: dist_names = sorted(index.distributions.keys()) errors = [] caches = {} for dist_name in dist_names: try: cache = generate_release_cache(index, dist_name, preclean, debug) except RuntimeError as e: errors.append(str(e)) continue caches[dist_name] = cache if errors: raise RuntimeError('\n'.join(errors)) return caches def generate_release_cache(index, dist_name, preclean=False, debug=False): dist, cache = _get_cached_release(index, dist_name, preclean) # fetch all manifests print('- fetch missing manifests') errors = [] for pkg_name in sorted(dist.packages.keys()): repo = dist.repositories[dist.packages[pkg_name].repository_name] if repo.version is None: if debug: print(' - skip "%s" since it has no version' % pkg_name) continue if debug: print(' - fetch "%s"' % pkg_name) else: sys.stdout.write('.') sys.stdout.flush() # check that package.xml is fetchable package_xml = dist.get_package_xml(pkg_name) if not package_xml: errors.append('%s: missing package.xml file for package "%s"' % (dist_name, pkg_name)) continue # check that package.xml is parseable try: pkg = parse_package_string(package_xml) except InvalidPackage: errors.append('%s: invalid package.xml file for package "%s"' % (dist_name, pkg_name)) continue # check that version numbers match (at least without deb inc) if not re.match('^%s(-[\dA-z~\+\.]+)?$' % re.escape(pkg.version), repo.version): errors.append('%s: different version in package.xml (%s) for package "%s" than for the repository (%s) (after removing the debian increment)' % (dist_name, pkg.version, pkg_name, repo.version)) if not debug: print('') if errors: raise RuntimeError('\n'.join(errors)) return cache def _get_cached_release(index, dist_name, preclean=False): print('Build cache for "%s"' % dist_name) cache = None try: if not preclean: print('- trying to use local cache') yaml_str = None if os.path.exists('%s-cache.yaml.gz' % dist_name): print('- use local file "%s-cache.yaml.gz"' % dist_name) with gzip.open('%s-cache.yaml.gz' % dist_name, 'rb') as f: yaml_str = f.read() elif os.path.exists('%s-cache.yaml' % dist_name): print('- use local file "%s-cache.yaml"' % dist_name) with open('%s-cache.yaml' % dist_name, 'r') as f: yaml_str = f.read() if yaml_str is not None: data = yaml.safe_load(yaml_str) cache = ReleaseCache(dist_name, data) if not cache: print('- trying to fetch cache') # get release cache cache = get_release_cache(index, dist_name) except: print('- failed to fetch old cache') if cache: print('- update cache') # get current release file rel_file_data = _get_dist_file_data(index, dist_name, 'release') # since format 2 of the index file might contain a single value rather then a list if not isinstance(rel_file_data, list): rel_file_data = [rel_file_data] # update cache with current release file cache.update_distribution(rel_file_data) else: print('- build cache from scratch') # get empty cache with distribution file distribution_file_data = _get_dist_file_data(index, dist_name, 'distribution') cache = ReleaseCache(dist_name, distribution_file_data=distribution_file_data) # get distribution return get_cached_release(index, dist_name, cache=cache, allow_lazy_load=True), cache rosdistro-0.8.0/src/rosdistro/release_file.py000066400000000000000000000114431357352161700213740ustar00rootroot00000000000000# Software License Agreement (BSD License) # # Copyright (c) 2013, Open Source Robotics Foundation, Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # * Redistributions in binary form must reproduce the above # copyright notice, this list of conditions and the following # disclaimer in the documentation and/or other materials provided # with the distribution. # * Neither the name of Open Source Robotics Foundation, Inc. nor # the names of its contributors may be used to endorse or promote # products derived from this software without specific prior # written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. from .package import Package from .release_repository_specification import ReleaseRepositorySpecification class ReleaseFile(object): _type = 'distribution' def __init__(self, name, data): self.name = name assert 'type' in data and data['type'] != 'release', "Unable to handle 'release' format anymore, please update your 'release' file to the latest specification" assert 'type' in data, "Expected file type is '%s'" % ReleaseFile._type assert data['type'] == ReleaseFile._type, "Expected file type is '%s', not '%s'" % (ReleaseFile._type, data['type']) assert 'version' in data, "Release file for '%s' lacks required version information" % self.name assert int(data['version']) == 1, "Unable to handle '%s' format version '%d', please update rosdistro (e.g. on Ubuntu/Debian use: sudo apt-get update && sudo apt-get install --only-upgrade python-rosdistro)" % (ReleaseFile._type, int(data['version'])) self.version = int(data['version']) self.repositories = {} self.packages = {} if 'repositories' in data: for repo_name in sorted(data['repositories'].keys()): if 'release' not in data['repositories'][repo_name]: continue repo_status_data = data['repositories'][repo_name] repo_data = repo_status_data['release'] try: repo = ReleaseRepositorySpecification(repo_name, repo_data) # for backward compatibility only repo.status = repo_status_data.get('status', None) repo.status_description = repo_status_data.get('status_description', None) except AssertionError as e: e.args = [("Release file '%s': %s" % (self.name, a) if i == 0 else a) for i, a in enumerate(e.args)] raise e self.repositories[repo_name] = repo if repo.package_names: for pkg_name in repo.package_names: assert pkg_name not in self.packages, "Duplicate package name '%s' exists in repository '%s' as well as in repository '%s'" % (pkg_name, repo_name, self.packages[pkg_name].repository_name) self._add_package(pkg_name, repo, unary_repo=len(repo.package_names) == 1 and pkg_name == repo_name) else: # no package means a single package in the root of the repository self._add_package(repo_name, repo, {'subfolder': '.'}, True) self.platforms = {} if 'release_platforms' in data: for os_name in data['release_platforms'].keys(): self.platforms[os_name] = [] for os_code_name in data['release_platforms'][os_name]: assert os_code_name not in self.platforms[os_name], "Distribution '%s' specifies the os_code_name '%s' multiple times for the os_name '%s'" % (self.name, os_code_name, os_name) self.platforms[os_name].append(os_code_name) def _add_package(self, pkg_name, repo, unary_repo): assert pkg_name not in self.packages self.packages[pkg_name] = Package(pkg_name, repo.name) rosdistro-0.8.0/src/rosdistro/release_repository_specification.py000066400000000000000000000064511357352161700255770ustar00rootroot00000000000000# Software License Agreement (BSD License) # # Copyright (c) 2013, Open Source Robotics Foundation, Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # * Redistributions in binary form must reproduce the above # copyright notice, this list of conditions and the following # disclaimer in the documentation and/or other materials provided # with the distribution. # * Neither the name of Open Source Robotics Foundation, Inc. nor # the names of its contributors may be used to endorse or promote # products derived from this software without specific prior # written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. from .repository_specification import RepositorySpecification class ReleaseRepositorySpecification(RepositorySpecification): def __init__(self, name, data): super(ReleaseRepositorySpecification, self).__init__(name, data) assert self.type == 'git' self.tags = {} if self.version is not None: assert 'tags' in data assert 'release' in data['tags'] if 'tags' in data: for tag_type in data['tags']: tag_data = data['tags'][tag_type] self.tags[tag_type] = str(tag_data) self.package_names = [] if 'packages' in data and data['packages']: self.package_names = sorted(data['packages']) else: # no packages means a single package self.package_names = [self.name] # for backward compatibility only self.release_repository = self def get_release_tag(self, pkg_name): data = { 'package': pkg_name } if self.version: data['version'] = self.version data['upstream_version'] = self.version.split('-')[0] release_tag = self.tags['release'] for k, v in data.items(): release_tag = release_tag.replace('{%s}' % k, v) return release_tag def get_data(self): data = self._get_data(skip_git_type=True) if self.tags: data['tags'] = {} for tag in self.tags: data['tags'][tag] = str(self.tags[tag]) if len(self.package_names) > 1 or (len(self.package_names) == 1 and self.package_names[0] != self.name): data['packages'] = sorted(self.package_names) return data rosdistro-0.8.0/src/rosdistro/repository.py000066400000000000000000000104351357352161700211740ustar00rootroot00000000000000# Software License Agreement (BSD License) # # Copyright (c) 2013, Open Source Robotics Foundation, Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # * Redistributions in binary form must reproduce the above # copyright notice, this list of conditions and the following # disclaimer in the documentation and/or other materials provided # with the distribution. # * Neither the name of Open Source Robotics Foundation, Inc. nor # the names of its contributors may be used to endorse or promote # products derived from this software without specific prior # written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. from .doc_repository_specification import DocRepositorySpecification from .release_repository_specification import ReleaseRepositorySpecification from .source_repository_specification import SourceRepositorySpecification from .status import valid_statuses class Repository(object): def __init__(self, name, doc_data, release_data, source_data, status_data): self.name = name self.doc_repository = DocRepositorySpecification(self.name, doc_data) if doc_data else None self.release_repository = ReleaseRepositorySpecification(self.name, release_data) if release_data else None self.source_repository = SourceRepositorySpecification(self.name, source_data) if source_data else None self.status = status_data.get('status', None) if self.status is not None: assert self.status in valid_statuses self.status_description = status_data.get('status_description', None) self.status_per_package = {} for pkg_name in status_data.get('status_per_package', {}): data = {} status = status_data.get('status_per_package')[pkg_name].get('status', None) if status: assert status in valid_statuses data['status'] = status status_description = status_data.get('status_per_package')[pkg_name].get('status_description', None) if status_description: data['status_description'] = status_description if data: self.status_per_package[pkg_name] = data def get_data(self): data = {} if self.doc_repository: data['doc'] = self.doc_repository.get_data() if self.release_repository: data['release'] = self.release_repository.get_data() if self.source_repository: data['source'] = self.source_repository.get_data() if self.status: data['status'] = self.status if self.status_description: data['status_description'] = self.status_description if self.status_per_package: data['status_per_package'] = {} for pkg_name in sorted(self.status_per_package.keys()): pkg_status = self.status_per_package[pkg_name] pkg_data = {} status = pkg_status.get('status', None) if status: pkg_data['status'] = status status_description = pkg_status.get('status_description', None) if status_description: pkg_data['status_description'] = status_description if pkg_data: data['status_per_package'][pkg_name] = pkg_data return data rosdistro-0.8.0/src/rosdistro/repository_specification.py000066400000000000000000000073051357352161700240760ustar00rootroot00000000000000# Software License Agreement (BSD License) # # Copyright (c) 2013, Open Source Robotics Foundation, Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # * Redistributions in binary form must reproduce the above # copyright notice, this list of conditions and the following # disclaimer in the documentation and/or other materials provided # with the distribution. # * Neither the name of Open Source Robotics Foundation, Inc. nor # the names of its contributors may be used to endorse or promote # products derived from this software without specific prior # written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. import re from .vcs import Git class RepositorySpecification(object): # Match groups are server and path on server. VCS_REGEX = re.compile('(?:https?:\/\/|ssh:\/\/|git:\/\/|git@)((?:[a-fA-F0-9]{40}@)?[\w.-]+)[:/]([\w/-]*)(?:\.git)?$') def __init__(self, name, data): self.name = name self.type = data.get('type', 'git') assert 'url' in data and data['url'], "Repository '%s' lacks required URL information" % name self.url = data['url'] self.version = data.get('version', None) self._remote_refs = None # for backward compatibility only self.status = None self.status_description = None def get_data(self): return self._get_data() def get_url_parts(self): """ Returns a tuple for the server and path, eg ('github.com', 'ros/catkin') """ match = self.VCS_REGEX.match(self.url) if not match: raise RuntimeError('VCS url "%s" does not match expected format.' % self.url) return match.groups() def has_remote_tag(self, tag): return tag in self.remote_tags @property def remote_refs(self): if not self._remote_refs: result = Git().command('ls-remote', self.url) if result['returncode'] != 0: raise RuntimeError('Could not git ls-remote repository "%s"' % self.url) self._remote_refs = {} for row in result['output'].strip().splitlines(): sha, name = row.split('\t') self._remote_refs[name] = sha return self._remote_refs @property def remote_tags(self): result = {} for name, sha in self.remote_refs.items(): if name.startswith('refs/tags/'): result[name.split('refs/tags/')[1]] = sha return result def _get_data(self, skip_git_type=False): data = {} if self.type != 'git' or not skip_git_type: data['type'] = str(self.type) data['url'] = str(self.url) if self.version is not None: data['version'] = self.version return data rosdistro-0.8.0/src/rosdistro/rosdistro.py000066400000000000000000000350171357352161700210100ustar00rootroot00000000000000import copy import os import sys import tarfile import tempfile import threading try: from urllib.request import urlopen from urllib.error import HTTPError except ImportError: from urllib2 import urlopen from urllib2 import HTTPError import yaml from .common import error from .common import info from .common import warning RES_DICT = {'build': [], 'buildtool': [], 'test': [], 'run': []} RES_TREE = {'build': {}, 'buildtool': {}, 'test': {}, 'run': {}} CACHE_VERSION = 1 walks = { 'FULL_WALK': {'build': ['build', 'run', 'buildtool', 'test'], 'run': ['build', 'run', 'buildtool', 'test'], 'buildtool': ['build', 'run', 'buildtool', 'test'], 'test': ['build', 'run', 'buildtool', 'test']}, 'SPIRAL_OF_DOOM': {'build': ['run'], 'run': ['buildtool'], 'buildtool': ['test'], 'test': ['build']} } def invert_dict(d): inverted = {} for key, value in d.iteritems(): for v in value: v_keys = inverted.setdefault(v, []) if key not in v_keys: v_keys.append(key) return inverted class RosDistro: def __init__(self, name, cache_location=None): self.depends_on1_cache = copy.deepcopy(RES_TREE) t1 = threading.Thread(target=self._construct_rosdistro_file, args=(name,)) t2 = threading.Thread(target=self._construct_rosdistro_dependencies, args=(name, cache_location,)) t1.start() t2.start() t1.join() t2.join() def _construct_rosdistro_file(self, name): self.distro_file = RosDistroFile(name) def _construct_rosdistro_dependencies(self, name, cache_location): self.depends_file = RosDependencies(name, cache_location) def get_repositories(self): return self.distro_file.repositories def get_repository(self, repo): return self.get_repositories()[repo] def get_packages(self): return self.distro_file.packages def get_package(self, pkg): return self.get_packages()[pkg] def get_rosinstall(self, items, version='last_release', source='vcs'): rosinstall = "" for p in self._convert_to_pkg_list(items): rosinstall += p.get_rosinstall(version, source, self.distro_file.name) return rosinstall def _get_depends_on1(self, package_name): if package_name in self.depends_on1_cache: return self.depends_on1_cache[package_name] res = copy.deepcopy(RES_DICT) for pkg in self.get_packages(): for key, depends in self._get_depends1(pkg).iteritems(): if package_name in depends: res[key].append(pkg) self.depends_on1_cache[package_name] = res return res def get_depends_on1(self, items): return self.get_depends_on(items, 1) def get_depends_on(self, items, depth=0, dep_dict=walks['FULL_WALK']): res = copy.deepcopy(RES_DICT) for p in self._convert_to_pkg_list(items): for dep_type, dep_list in res.iteritems(): self._get_depends_on_recursive(p.name, dep_type, invert_dict(dep_dict), dep_list, depth, 1) return res def _get_depends_on_recursive(self, package_name, dep_type, dep_dict, res, depth, curr_depth): deps_on = self._get_depends_on1(package_name) # merge and recurse for d in deps_on[dep_type]: if d not in res: res.append(d) if depth == 0 or curr_depth < depth: for next_dep_type in dep_dict[dep_type]: self._get_depends_on_recursive(d, next_dep_type, dep_dict, res, depth, curr_depth + 1) def _get_depends1(self, package_name): p = self.distro_file.packages[package_name] return self.depends_file.get_dependencies(p, self.distro_file.name) def get_depends1(self, items): return self.get_depends(items, 1) def get_depends(self, items, depth=0, dep_dict=walks['FULL_WALK']): res = copy.deepcopy(RES_DICT) for p in self._convert_to_pkg_list(items): for dep_type, dep_list in res.iteritems(): self._get_depends_recursive(p.name, dep_type, dep_dict, dep_list, depth, 1) return res def _get_depends_recursive(self, package_name, dep_type, dep_dict, res, depth, curr_depth): deps1 = self._get_depends1(package_name) # merge and recurse for d in deps1[dep_type]: if d not in res: res.append(d) if depth == 0 or curr_depth < depth: if d in self.get_packages(): # recurse on packages only for next_dep_type in dep_dict[dep_type]: self._get_depends_recursive(d, next_dep_type, dep_dict, res, depth, curr_depth + 1) def _convert_to_pkg_list(self, items): if type(items) != list: items = [items] pkgs = [] for i in items: if i in self.distro_file.repositories: for p in self.distro_file.repositories[i].packages: if p not in pkgs: pkgs.append(p) elif i in self.distro_file.packages: if not self.distro_file.packages[i] in pkgs: pkgs.append(self.distro_file.packages[i]) else: raise RuntimeError("!!! {0} is not a package name nor a repository name".format(i)) return pkgs class RosDistroFile: def __init__(self, name): self.packages = {} self.repositories = {} self.name = name # parse ros distro file distro_url = urlopen('https://raw.github.com/ros/rosdistro/master/releases/%s.yaml' % name) distro = yaml.load(distro_url.read())['repositories'] # loop over all repo's for repo_name, data in distro.iteritems(): repo = RosRepository(repo_name, data['version'], data['url']) self.repositories[repo_name] = repo if 'packages' not in data: # support unary disto's data['packages'] = {repo_name: ''} # loop over all packages for pkg_name in data['packages'].keys(): pkg = RosPackage(pkg_name, repo) repo.packages.append(pkg) self.packages[pkg_name] = pkg class RosRepository: def __init__(self, name, version, url): self.name = name self.version = version self.url = url self.packages = [] def get_rosinstall(self, version, source): return "\n".join([p.get_rosinstall(version, source) for p in self.packages]) class RosPackage: def __init__(self, name, repository): self.name = name self.repository = repository self._package_xmls = {} self._release_tags = {} def _fetch_package_xml(self, rosdistro): repo = self.repository if 'github.com' in repo.url: url = repo.url release_tag = 'release/{0}/{1}/{2}'.format(rosdistro, self.name, repo.version) url = url.replace('.git', '/{0}/package.xml'.format(release_tag)) url = url.replace('git://', 'https://') url = url.replace('https://', 'https://raw.') try: try: package_xml = urlopen(url).read() except Exception as e: msg = "Failed to read package.xml file from url '{0}': {1}".format(url, e) warning(msg) upstream_version = repo.version.split('-')[0] legacy_release_tag = 'release/{0}/{1}'.format(self.name, upstream_version) url = url.replace(release_tag, legacy_release_tag) info("Trying to read from legacy-style url '{0}' instead".format(url)) package_xml = urlopen(url).read() except Exception as e: msg += '\nAND\n' msg += "Failed to read package.xml file from url '{0}': {1}".format(url, e) raise RuntimeError(msg) self._package_xmls[rosdistro] = package_xml self._release_tags[rosdistro] = release_tag return package_xml, release_tag else: raise Exception("Non-github repositories are net yet supported by the rosdistro tool") def get_package_xml(self, rosdistro): if rosdistro not in self._package_xmls: self._fetch_package_xml(rosdistro) return self._package_xmls[rosdistro] def get_release_tag(self, rosdistro): if rosdistro not in self._release_tags: self._fetch_package_xml(rosdistro) return self._release_tags[rosdistro] def get_rosinstall(self, version, source, rosdistro): # can't get last release of unreleased repository if version == 'last_release' and not self.repository.version: raise RuntimeError("Can't get the last release of unreleased repository {0}".format(self.repository.name)) # set specific version of last release of needed if version == 'last_release': version = self.repository.version.split('-')[0] # generate the rosinstall file release_tag = self.get_release_tag(rosdistro) if version == 'master': return yaml.dump([{ 'git': { 'local-name': self.name, 'uri': self.repository.url, 'version': '/'.join(release_tag.split('/')[:-1]) }}], default_style=False) else: if source == 'vcs': return yaml.safe_dump([{ 'git': { 'local-name': self.name, 'uri': self.repository.url, 'version': release_tag }}], default_style=False) elif source == 'tar': uri = self.repository.url uri = uri.replace('git://', 'https://') uri = uri.replace('.git', '/archive/{0}.tar.gz'.format(release_tag)) return yaml.safe_dump([{ 'tar': { 'local-name': self.name, 'uri': uri, 'version': '{0}-release-{1}'.format(self.repository.name, release_tag.replace('/', '-')) }}], default_style=False) else: raise RuntimeError("Invalid source type {0}".format(source)) class RosDependencies: def __init__(self, name, cache_location): # url's self.file_name = '%s-dependencies.yaml' % name if cache_location: self.local_url = os.path.join(cache_location, self.file_name) else: from rospkg import environment self.local_url = os.path.join(environment.get_ros_home(), self.file_name) self.server_url = 'http://www.ros.org/rosdistro/%s-dependencies.tar.gz' % name self.dependencies = {} # initialize with the local or server cache deps = self._read_local_cache() if deps == {}: deps = self._read_server_cache() for key, value in deps.iteritems(): self.dependencies[key] = value if self.cache == 'server': self._write_local_cache() def get_dependencies(self, package, rosdistro): repo = package.repository # support unreleased stacks if not repo.version: return copy.deepcopy(RES_DICT) key = '%s?%s?%s' % (repo.name, repo.version, package.name) # check in memory first if key in self.dependencies: return self.dependencies[key] # read server cache if needed if self.cache != 'server': deps = self._read_server_cache() for key, value in deps.iteritems(): self.dependencies[key] = value self._write_local_cache() if key in self.dependencies: return self.dependencies[key] # retrieve dependencies deps = retrieve_dependencies(package.get_package_xml(rosdistro)) self.dependencies[key] = deps self._write_local_cache() return deps def _read_server_cache(self): self.cache = 'server' try: resp = urlopen(self.server_url) except HTTPError as ex: warning("Failed to read server cache: %s" % ex) return {} with tempfile.NamedTemporaryFile('w') as fh: fh.write(resp.read()) fh.flush() tar = tarfile.open(fh.name, 'r') data = tar.extractfile(self.file_name) deps = yaml.load(data.read()) if not deps \ or 'cache_version' not in deps \ or deps['cache_version'] != CACHE_VERSION \ or 'repositories' not in deps: raise return deps['repositories'] def _read_local_cache(self): try: self.cache = 'local' with open(self.local_url) as f: deps = yaml.safe_load(f.read()) if not deps \ or 'cache_version' not in deps \ or deps['cache_version'] != CACHE_VERSION \ or 'repositories' not in deps: raise return deps['repositories'] except Exception: return {} def _write_local_cache(self): try: try: os.makedirs(os.path.dirname(self.local_url)) except: pass with open(self.local_url, 'w') as f: yaml.dump({'cache_version': CACHE_VERSION, 'repositories': self.dependencies}, f) except Exception as ex: error("Failed to write local dependency cache to %s: %s" % (self.local_url, ex)) def retrieve_dependencies(package_xml): try: return get_package_dependencies(package_xml) except Exception: raise RuntimeError("Failed to get dependencies from package_xml:\n```\n{0}\n```".format(package_xml)) def get_package_dependencies(package_xml): if not os.path.abspath("/usr/lib/pymodules/python2.7") in sys.path: sys.path.append("/usr/lib/pymodules/python2.7") from catkin_pkg import package as catkin_pkg pkg = catkin_pkg.parse_package_string(package_xml) depends1 = {'build': [d.name for d in pkg.build_depends], 'buildtool': [d.name for d in pkg.buildtool_depends], 'test': [d.name for d in pkg.test_depends], 'run': [d.name for d in pkg.run_depends]} return depends1 rosdistro-0.8.0/src/rosdistro/source_build_file.py000066400000000000000000000145051357352161700224350ustar00rootroot00000000000000# Software License Agreement (BSD License) # # Copyright (c) 2013, Open Source Robotics Foundation, Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # * Redistributions in binary form must reproduce the above # copyright notice, this list of conditions and the following # disclaimer in the documentation and/or other materials provided # with the distribution. # * Neither the name of Open Source Robotics Foundation, Inc. nor # the names of its contributors may be used to endorse or promote # products derived from this software without specific prior # written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. import copy class SourceBuildFile(object): _type = 'source-build' def __init__(self, name, data): self.name = name assert 'type' in data, "Expected file type is '%s'" % SourceBuildFile._type assert data['type'] == SourceBuildFile._type, "Expected file type is '%s', not '%s'" % (SourceBuildFile._type, data['type']) assert 'version' in data, "Source build file for '%s' lacks required version information" % self.name assert int(data['version']) == 1, "Unable to handle '%s' format version '%d', please update rosdistro (e.g. on Ubuntu/Debian use: sudo apt-get update && sudo apt-get install --only-upgrade python-rosdistro)" % (SourceBuildFile._type, int(data['version'])) self.version = int(data['version']) self.repository_whitelist = [] if 'repository_whitelist' in data: self.repository_whitelist = data['repository_whitelist'] assert isinstance(self.repository_whitelist, list) self.repository_blacklist = [] if 'repository_blacklist' in data: self.repository_blacklist = data['repository_blacklist'] assert isinstance(self.repository_blacklist, list) self.notify_emails = [] self.notify_maintainers = None self.notify_committers = None if 'notifications' in data: if 'emails' in data['notifications']: self.notify_emails = data['notifications']['emails'] assert isinstance(self.notify_emails, list) if 'maintainers' in data['notifications'] and data['notifications']['maintainers']: self.notify_maintainers = True if 'committers' in data['notifications'] and data['notifications']['committers']: self.notify_committers = True assert 'targets' in data self._targets = {} for os_name in data['targets'].keys(): if os_name == '_config': self._targets[os_name] = data['targets'][os_name] continue self._targets[os_name] = {} for os_code_name in data['targets'][os_name]: if os_code_name == '_config': self._targets[os_name][os_code_name] = data['targets'][os_name][os_code_name] continue self._targets[os_name][os_code_name] = {} for arch in data['targets'][os_name][os_code_name]: self._targets[os_name][os_code_name][arch] = data['targets'][os_name][os_code_name][arch] assert 'jenkins_url' in data self.jenkins_url = str(data['jenkins_url']) self.jenkins_job_timeout = None if 'jenkins_job_timeout' in data: self.jenkins_job_timeout = int(data['jenkins_job_timeout']) def filter_repositories(self, repos): res = copy.copy(set(repos)) if self.repository_whitelist: res &= set(self.repository_whitelist) res -= set(self.repository_blacklist) return res def get_target_os_names(self): return [t for t in self._targets.keys() if t != '_config'] def get_target_os_code_names(self, os_name): os_code_names = self._targets[os_name] return [t for t in os_code_names.keys() if t != '_config'] def get_target_arches(self, os_name, os_code_name): arches = self._targets[os_name][os_code_name] return [t for t in arches.keys() if t != '_config'] def get_target_configuration(self, os_name=None, os_code_name=None, arch=None): assert os_code_name is not None or arch is None assert os_name is not None or os_code_name is None arches = self._targets[os_name][os_code_name] return [t for t in arches.keys() if t != '_config'] def get_data(self): data = {} data['type'] = SourceBuildFile._type data['version'] = 1 if self.repository_whitelist: data['repository_whitelist'] = self.repository_whitelist if self.repository_blacklist: data['repository_blacklist'] = self.repository_blacklist if self.notify_emails or self.notify_maintainers or self.notify_committers: data['notifications'] = {} if self.notify_emails: data['notifications']['emails'] = self.notify_emails if self.notify_maintainers is not None: data['notifications']['maintainers'] = bool(self.notify_maintainers) if self.notify_committers is not None: data['notifications']['committers'] = bool(self.notify_committers) data['targets'] = self._targets data['jenkins_url'] = self.jenkins_url if self.jenkins_job_timeout: data['jenkins_job_timeout'] = self.jenkins_job_timeout return data rosdistro-0.8.0/src/rosdistro/source_file.py000066400000000000000000000064451357352161700212620ustar00rootroot00000000000000# Software License Agreement (BSD License) # # Copyright (c) 2013, Open Source Robotics Foundation, Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # * Redistributions in binary form must reproduce the above # copyright notice, this list of conditions and the following # disclaimer in the documentation and/or other materials provided # with the distribution. # * Neither the name of Open Source Robotics Foundation, Inc. nor # the names of its contributors may be used to endorse or promote # products derived from this software without specific prior # written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. from .repository_specification import RepositorySpecification class SourceFile(object): _type = 'distribution' def __init__(self, name, data): self.name = name assert 'type' in data and data['type'] != 'source', "Unable to handle 'source' format anymore, please update your 'source' file to the latest specification" assert 'type' in data, "Expected file type is '%s'" % SourceFile._type assert data['type'] == SourceFile._type, "Expected file type is '%s', not '%s'" % (SourceFile._type, data['type']) assert 'version' in data, "Source file for '%s' lacks required version information" % self.name assert int(data['version']) == 1, "Unable to handle '%s' format version '%d', please update rosdistro (e.g. on Ubuntu/Debian use: sudo apt-get update && sudo apt-get install --only-upgrade python-rosdistro)" % (SourceFile._type, int(data['version'])) self.version = int(data['version']) self.repositories = {} if 'repositories' in data: for repo_name in sorted(data['repositories']): repo_data = data['repositories'][repo_name] if 'source' not in repo_data: continue repo_data = repo_data['source'] try: assert 'version' in repo_data, "Repository '%s' lacks required version information" % repo_name repo = RepositorySpecification(repo_name, repo_data) except AssertionError as e: e.args = [("Source file '%s': %s" % (self.name, a) if i == 0 else a) for i, a in enumerate(e.args)] raise e self.repositories[repo_name] = repo rosdistro-0.8.0/src/rosdistro/source_repository_cache.py000066400000000000000000000077631357352161700237110ustar00rootroot00000000000000# Software License Agreement (BSD License) # # Copyright (c) 2018, Open Source Robotics Foundation, Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # * Redistributions in binary form must reproduce the above # copyright notice, this list of conditions and the following # disclaimer in the documentation and/or other materials provided # with the distribution. # * Neither the name of Open Source Robotics Foundation, Inc. nor # the names of its contributors may be used to endorse or promote # products derived from this software without specific prior # written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. class SourceRepositoryCache(object): """ This class represents a cache of the package XML strings for all packages in a single repo at a particular moment in time. A dictionary of many of these (one for each repo) keyed to the repo name represents the totality of the source package xml cache. """ def __init__(self, data): assert data self._ref = data['_ref'] self._package_names = set([name for name in data.keys() if name != '_ref']) self._data = data def get_data(self): """ Return the bare data dict, suitable for serializing into yaml. """ return self._data @classmethod def from_ref(cls, ref): """ Create a new empty cache instance from just the version control reference hash. """ return cls({'_ref': ref}) def add(self, package_name, package_path, package_xml_string): """ Add a package to the cache. """ self._data[package_name] = (package_path, package_xml_string) self._package_names.add(package_name) def __iter__(self): """ Iterate the list of package names in this cached repo. Returns an iterator of str. """ return iter(self._package_names) def __getitem__(self, package_name): """ Access the cached information about a specific package. Returns a (str, str) of path to package relative to repo root, and string of package xml. """ if package_name not in self._package_names: raise KeyError("Package '%s' not present in SourceRepositoryCache." % package_name) return self._data[package_name] def items(self): """ Generator of (str, str, str) containing the package name, path relative to repo root, and package xml string. """ for package_name in self._package_names: package_path, package_xml_string = self._data[package_name] yield package_name, package_path, package_xml_string def __len__(self): """ Returns the number of packages in this repo. """ return len(self._package_names) def keys(self): """ Return the list of packages in the repo cache. """ return self._package_names def ref(self): """ Return the version control hash. """ return self._ref rosdistro-0.8.0/src/rosdistro/source_repository_specification.py000066400000000000000000000051451357352161700254560ustar00rootroot00000000000000# Software License Agreement (BSD License) # # Copyright (c) 2014, Open Source Robotics Foundation, Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # * Redistributions in binary form must reproduce the above # copyright notice, this list of conditions and the following # disclaimer in the documentation and/or other materials provided # with the distribution. # * Neither the name of Open Source Robotics Foundation, Inc. nor # the names of its contributors may be used to endorse or promote # products derived from this software without specific prior # written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. from .repository_specification import RepositorySpecification class SourceRepositorySpecification(RepositorySpecification): def __init__(self, name, data): super(SourceRepositorySpecification, self).__init__(name, data) self.test_commits = None if 'test_commits' in data: self.test_commits = bool(data['test_commits']) self.test_pull_requests = None if 'test_pull_requests' in data: self.test_pull_requests = bool(data['test_pull_requests']) self.test_abi = None if 'test_abi' in data: self.test_abi = bool(data['test_abi']) def get_data(self): data = self._get_data(skip_git_type=False) if self.test_commits is not None: data['test_commits'] = self.test_commits if self.test_pull_requests is not None: data['test_pull_requests'] = self.test_pull_requests if self.test_abi is not None: data['test_abi'] = self.test_abi return data rosdistro-0.8.0/src/rosdistro/status.py000066400000000000000000000035521357352161700203020ustar00rootroot00000000000000# Software License Agreement (BSD License) # # Copyright (c) 2013, Open Source Robotics Foundation, Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # * Redistributions in binary form must reproduce the above # copyright notice, this list of conditions and the following # disclaimer in the documentation and/or other materials provided # with the distribution. # * Neither the name of Open Source Robotics Foundation, Inc. nor # the names of its contributors may be used to endorse or promote # products derived from this software without specific prior # written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. STATUS_DEVELOPED = 'developed' STATUS_MAINTAINED = 'maintained' STATUS_UNMAINTAINED = 'unmaintained' STATUS_END_OF_LIFE = 'end-of-life' valid_statuses = [ STATUS_DEVELOPED, STATUS_MAINTAINED, STATUS_UNMAINTAINED, STATUS_END_OF_LIFE ] rosdistro-0.8.0/src/rosdistro/vcs.py000066400000000000000000000064771357352161700175630ustar00rootroot00000000000000# Software License Agreement (BSD License) # # Copyright (c) 2013, Open Source Robotics Foundation, Inc. # Copyright (c) 2016, Clearpath Robotics # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # * Redistributions in binary form must reproduce the above # copyright notice, this list of conditions and the following # disclaimer in the documentation and/or other materials provided # with the distribution. # * Neither the name of Open Source Robotics Foundation, Inc. nor # the names of its contributors may be used to endorse or promote # products derived from this software without specific prior # written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. import os import re import subprocess from distutils.version import LooseVersion class Git(object): _client_executable = None _client_version = None def __init__(self, cwd=None): self.cwd = cwd if not self._client_executable: self.__class__._client_executable = _find_executable('git') def command(self, *args): assert self._client_executable is not None, "'git' not found" return _run_command((self._client_executable,) + args, self.cwd) @classmethod def version_gte(cls, version): if not cls._client_version: result = cls().command('--version') cls._client_version = result['output'].split()[-1] return LooseVersion(cls._client_version) >= LooseVersion(version) def ref_is_hash(ref): return re.match('^[0-9a-f]{40}$', ref) is not None def _run_command(cmd, cwd=None, env=None): result = {'cmd': ' '.join(cmd), 'cwd': cwd} try: proc = subprocess.Popen(cmd, cwd=cwd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, env=env) output, _ = proc.communicate() result['output'] = output.rstrip() result['returncode'] = proc.returncode except subprocess.CalledProcessError as e: result['output'] = e.output result['returncode'] = e.returncode if not isinstance(result['output'], str): result['output'] = result['output'].decode('utf-8') return result def _find_executable(file_name): for path in os.getenv('PATH').split(os.path.pathsep): file_path = os.path.join(path, file_name) if os.path.isfile(file_path) and os.access(file_path, os.X_OK): return file_path return None rosdistro-0.8.0/src/rosdistro/verify.py000066400000000000000000000143061357352161700202620ustar00rootroot00000000000000# Software License Agreement (BSD License) # # Copyright (c) 2013, Open Source Robotics Foundation, Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # * Redistributions in binary form must reproduce the above # copyright notice, this list of conditions and the following # disclaimer in the documentation and/or other materials provided # with the distribution. # * Neither the name of Open Source Robotics Foundation, Inc. nor # the names of its contributors may be used to endorse or promote # products derived from this software without specific prior # written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. from __future__ import print_function import difflib import sys import yaml from . import get_distribution_file, get_distribution_files, get_doc_build_files, get_doc_file, get_index, get_release_build_files, get_release_file, get_source_build_files, get_source_file from .loader import load_url def verify_files_parsable(index_url): return verify_files(index_url, _check_files_parsable, include_deprecated=False) def _check_files_parsable(index, dist_name, loader_function, _yaml_url, _file_type): try: loader_function(index, dist_name) except Exception as e: print(str(e), file=sys.stderr) return False return True def reformat_files(index_url): return verify_files(index_url, _reformat_files) def verify_files_identical(index_url): return verify_files(index_url, _check_files_identical) def verify_files(index_url, callback, include_deprecated=False): identical = True index = get_index(index_url) for dist_name in sorted(index.distributions.keys()): dist = index.distributions[dist_name] if index.version < 3: providers = [get_distribution_file] else: providers = [get_distribution_files] if include_deprecated: providers.extend([get_release_file, get_source_file, get_doc_file]) file_providers = { 'distribution': (providers, 'distribution'), } if index.version < 3: file_providers.update({ 'release_builds': (get_release_build_files, 'release-build'), 'source_builds': (get_source_build_files, 'source-build'), 'doc_builds': (get_doc_build_files, 'doc-build') }) for key in sorted(file_providers.keys()): provider, file_type = file_providers[key] yaml_url = dist[key] if isinstance(provider, list): for p in provider: identical &= callback(index, dist_name, p, yaml_url, file_type) else: identical &= callback(index, dist_name, provider, yaml_url, file_type) return identical def _reformat_files(index, dist_name, loader_function, yaml_url, file_type): all_identical = True files = loader_function(index, dist_name) if not isinstance(files, list): files = [files] yaml_url = [yaml_url] for i, f in enumerate(files): url = yaml_url[i] if not url.startswith('file://'): print('Skipping non-file url: %s' % url) continue identical = _check_file_identical(f, yaml_url[i], file_type) all_identical &= identical path = url[7:] if identical: print('Skipping identical file: %s' % path) continue print('Updating file: %s' % path) data = f.get_data() dist_file_data = _to_yaml(data) dist_file_data = '\n'.join(_yaml_header_lines(file_type, data['version'])) + '\n' + dist_file_data with open(path, 'w') as f: f.write(dist_file_data) return all_identical def _check_files_identical(index, dist_name, loader_function, yaml_url, file_type): identical = True files = loader_function(index, dist_name) if not isinstance(files, list): files = [files] yaml_url = [yaml_url] for i, f in enumerate(files): identical &= _check_file_identical(f, yaml_url[i], file_type) return identical def _check_file_identical(dist_file, yaml_url, file_type): yaml_str = load_url(yaml_url) yaml_lines = yaml_str.splitlines() dist_file_data = dist_file.get_data() dist_file_lines = _to_yaml(dist_file_data).splitlines() dist_file_lines[0:0] = _yaml_header_lines(file_type, dist_file_data['version']) if yaml_lines != dist_file_lines: diff = difflib.unified_diff( yaml_lines, dist_file_lines, yaml_url, 'loaded-and-saved', n=1, lineterm='') for line in diff: print(line, file=sys.stderr) return False return True def _to_yaml(data): yaml_str = yaml.dump(data, default_flow_style=False) yaml_str = yaml_str.replace(': null', ':') yaml_str = yaml_str.replace(': {}', ':') return yaml_str def _yaml_header_lines(file_type, version): rep = '141' if file_type == 'index': if version == 3: rep = '143' elif version == 4: rep = '153' if file_type == 'distribution' and version == 2: rep = '143' return [ '%YAML 1.1', '# ROS %s file' % file_type, '# see REP %s: http://ros.org/reps/rep-0%s.html' % (rep, rep), '---' ] rosdistro-0.8.0/src/rosdistro/writer.py000066400000000000000000000037651357352161700203010ustar00rootroot00000000000000# Software License Agreement (BSD License) # # Copyright (c) 2013, Open Source Robotics Foundation, Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # * Redistributions in binary form must reproduce the above # copyright notice, this list of conditions and the following # disclaimer in the documentation and/or other materials provided # with the distribution. # * Neither the name of Open Source Robotics Foundation, Inc. nor # the names of its contributors may be used to endorse or promote # products derived from this software without specific prior # written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. from __future__ import print_function from .verify import _to_yaml, _yaml_header_lines def yaml_from_distribution_file(distribution_file): return '\n'.join(_yaml_header_lines(distribution_file._type, distribution_file.version)) + '\n' + _to_yaml(distribution_file.get_data()) # for backward compatibility only def yaml_from_release_file(release_file): raise NotImplementedError rosdistro-0.8.0/stdeb.cfg000066400000000000000000000025551357352161700153520ustar00rootroot00000000000000[rosdistro] Debian-Version: 100 ; rosdistro-modules same version as in: ; - setup.py ; - src/rosdistro/__init__.py Depends: ca-certificates, python-argparse, python-rosdistro-modules (>= 0.8.0), python-setuptools, python-yaml ; rosdistro-modules same version as in: ; - setup.py ; - src/rosdistro/__init__.py Depends3: ca-certificates, python3-rosdistro-modules (>= 0.8.0), python3-setuptools, python3-yaml Conflicts: python3-rosdistro Conflicts3: python-rosdistro Copyright-File: LICENSE.txt Suite: xenial yakkety zesty artful bionic cosmic disco eoan jessie stretch buster Suite3: xenial yakkety zesty artful bionic cosmic disco eoan focal jessie stretch buster X-Python3-Version: >= 3.4 Setup-Env-Vars: SKIP_PYTHON_MODULES=1 [rosdistro_modules] Depends: ca-certificates, python-catkin-pkg-modules, python-rospkg-modules, python-setuptools, python-yaml Depends3: ca-certificates, python3-catkin-pkg-modules, python3-rospkg-modules, python3-setuptools, python3-yaml Conflicts: python-rosdistro (<< 0.6.0) Conflicts3: python3-rosdistro (<< 0.6.0) Replaces: python-rosdistro (<< 0.6.0) Replaces3: python3-rosdistro (<< 0.6.0) Copyright-File: LICENSE.txt Suite: xenial yakkety zesty artful bionic cosmic disco eoan jessie stretch buster Suite3: xenial yakkety zesty artful bionic cosmic disco eoan focal jessie stretch buster X-Python3-Version: >= 3.4 Setup-Env-Vars: SKIP_PYTHON_SCRIPTS=1 rosdistro-0.8.0/test/000077500000000000000000000000001357352161700145405ustar00rootroot00000000000000rosdistro-0.8.0/test/files/000077500000000000000000000000001357352161700156425ustar00rootroot00000000000000rosdistro-0.8.0/test/files/foo/000077500000000000000000000000001357352161700164255ustar00rootroot00000000000000rosdistro-0.8.0/test/files/foo/distribution.yaml000066400000000000000000000026751357352161700220420ustar00rootroot00000000000000%YAML 1.1 # ROS distribution file # see REP 141: http://ros.org/reps/rep-0141.html --- release_platforms: debian: - wheezy ubuntu: - precise - quantal - raring repositories: bar_repo: doc: type: git url: https://github.com/example-test/bar_repo.git version: master release: tags: release: release/foo/{package}/{version} url: https://github.com/example-release/bar_repo.git version: 0.1.2 source: type: git url: https://github.com/example-test/bar_repo.git version: master baz-repo: doc: blacklist_packages: - baz_pkg2 depends: - bar_repo type: hg url: https://bitbucket.org/baz-test/baz-repo version: default release: packages: - baz_pkg1 - baz_pkg2 tags: release: release/foo/{package}/{version} url: https://example.com/release/baz-repo.git version: 7.7.7-7 source: type: hg url: https://bitbucket.org/baz-test/baz-repo version: default status: maintained status_description: With a lot of passion status_per_package: baz_pkg2: status: end-of-life status_description: The package has not been updated since 1995 release_only_repo: release: tags: release: release/foo/{package}/{version} url: https://github.com/example-release/release_only_repo.git version: 1.2.3 type: distribution version: 1 rosdistro-0.8.0/test/files/foo/distribution2.yaml000066400000000000000000000002541357352161700221130ustar00rootroot00000000000000%YAML 1.1 # ROS distribution file # see REP 141: http://ros.org/reps/rep-0141.html --- release_platforms: ubuntu: - precise repositories: type: distribution version: 1 rosdistro-0.8.0/test/files/foo/distribution3.yaml000066400000000000000000000002531357352161700221130ustar00rootroot00000000000000%YAML 1.1 # ROS distribution file # see REP 141: http://ros.org/reps/rep-0141.html --- release_platforms: ubuntu: - trusty repositories: type: distribution version: 1 rosdistro-0.8.0/test/files/foo/doc-build.yaml000066400000000000000000000007511357352161700211560ustar00rootroot00000000000000%YAML 1.1 # ROS doc-build file # see REP 141: http://ros.org/reps/rep-0141.html --- doc_tag_index_repository: url: git@github.com/ros-infrastructure/rosdoc_tag_index version: master jenkins_job_timeout: 23 jenkins_url: http://farm.example.com:8080 notifications: emails: - admin@example.com maintainers: true targets: _config: apt_mirrors: - http://repo.example.com/ - http://archive.ubuntu.com/ubuntu ubuntu: precise: amd64: type: doc-build version: 1 rosdistro-0.8.0/test/files/foo/release-build.yaml000066400000000000000000000011401357352161700220220ustar00rootroot00000000000000%YAML 1.1 # ROS release-build file # see REP 141: http://ros.org/reps/rep-0141.html --- jenkins_binarydeb_job_timeout: 42 jenkins_sourcedeb_job_timeout: 5 jenkins_url: http://farm.example.com:8080 notifications: emails: - admin@example.com sync: package_count: 123 targets: _config: apt_target_repository: http://repo.example.com/ foo: bar ubuntu: _config: bar: baz precise: _config: ping: pong amd64: _config: foo: baz i386: quantal: amd64: i386: raring: amd64: i386: type: release-build version: 1 rosdistro-0.8.0/test/files/foo/release-cache.yaml000066400000000000000000000174371357352161700220060ustar00rootroot00000000000000distribution_file: release_platforms: debian: - wheezy ubuntu: - precise - quantal - raring repositories: bar_repo: doc: type: git url: https://github.com/example-test/bar_repo.git version: master release: tags: release: release/foo/{package}/{version} url: https://github.com/example-release/bar_repo.git version: 0.1.2 source: type: git url: https://github.com/example-test/bar_repo.git version: master baz-repo: doc: type: hg url: https://bitbucket.org/baz-test/baz-repo version: default release: packages: - baz_pkg1 - baz_pkg2 tags: release: release/foo/{package}/{version} url: https://example.com/release/baz-repo.git version: 7.7.7-7 source: type: hg url: https://bitbucket.org/baz-test/baz-repo version: default status: maintained status_description: With a lot of passion status_per_package: baz_pkg2: status: end-of-life status_description: The package has not been updated since 1995 type: distribution version: 1 name: foo release_package_xmls: {actionlib_msgs: "\n actionlib_msgs\n 1.9.14\n\ \ \n actionlib_msgs defines the common messages to interact\ \ with an\n action server and an action client. For full documentation of\n\ \ the actionlib API see\n the actionlib\n package.\n \n Tully Foote\n BSD\n\n http://ros.org/wiki/actionlib_msgs\n\ \ Vijay Pradeep\n\n catkin\n\ \n message_generation\n std_msgs\n\ \n message_generation \n message_runtime\n std_msgs\n\ \n", catkin: "\n\n catkin\n\ \ 0.5.63\n Low-level build system macros and\ \ infrastructure for ROS.\n Dirk Thomas\n BSD\n\n http://www.ros.org/wiki/catkin\n https://github.com/ros/catkin/issues\n\ \ https://github.com/ros/catkin\n\n Troy\ \ Straszheim\n Morten Kjaergaard\n Brian Gerkey\n\ \ Dirk Thomas\n\n gtest\n python-argparse\n\ \ python-catkin-pkg\n python-empy\n\ \ python-nose\n\n cmake\n\ \n cmake\n gtest\n python-argparse\n\ \ python-catkin-pkg\n python-empy\n\ \ python-nose\n\n \n \n \n\n", common_msgs: "\n common_msgs\n\ \ 1.9.14\n \n common_msgs contains messages\ \ that are widely used by other ROS packages.\n These includes messages for\n\ \ actions (actionlib_msgs),\n\ \ diagnostics (diagnostic_msgs),\n\ \ geometric primitives (geometry_msgs),\n\ \ robot navigation (nav_msgs),\n\ \ and common sensors (sensor_msgs),\ \ such as laser range finders, cameras, point clouds.\n \n Tully Foote\n BSD\n\ \n http://www.ros.org/wiki/common_msgs\n\n actionlib_msgs\n\ \ diagnostic_msgs\n geometry_msgs\n\ \ nav_msgs\n sensor_msgs\n\ \ shape_msgs\n stereo_msgs\n\ \ trajectory_msgs\n visualization_msgs\n\ \n \n \n \n\n", control: "\n\ \ control\n 1.1.6\n \n This\ \ package is essentially an alias for control_msgs, for backward compatibility.\ \ Do not depend on this package.\n \n Stuart Glaser\n Willow Garage\n\n BSD\n\n http://ros.org/wiki/control_msgs\n\ \n control_msgs\n\n control_msgs\n\ \n \n \n \n\n\n", control_msgs: "\n\ \ control_msgs\n 1.1.6\n \n \ \ control_msgs contains base messages and actions useful for\n controlling\ \ robots. It provides representations for controller\n setpoints and joint\ \ and cartesian trajectories.\n \n Stuart Glaser\n Willow Garage\n\n BSD\n\n http://ros.org/wiki/control_msgs\n\ \n catkin\n\n message_generation\n\ \ std_msgs\n trajectory_msgs\n\ \ geometry_msgs\n actionlib_msgs\n\ \n\n message_runtime\n std_msgs\n\ \ trajectory_msgs\n geometry_msgs\n\ \ actionlib_msgs\n\n\n", diagnostic_msgs: "\n\ \ diagnostic_msgs\n 1.9.14\n \n\ \ This package holds the diagnostic messages which provide the\n standardized\ \ interface for the diagnostic and runtime monitoring\n systems in ROS. These\ \ messages are currently used by\n the diagnostics\n Stack, which provides libraries for simple ways to set and\ \ access\n the messages, as well as automated ways to process the diagnostic\n\ \ data.\n\n These messages are used for long term logging and will not be\n\ \ changed unless there is a very important reason.\n \n Tully Foote\n BSD\n\ \n http://ros.org/wiki/diagnostic_msgs\n Tully Foote\n\n catkin\n\n message_generation\n\ \ std_msgs\n\n message_runtime\n\ \ std_msgs\n\n"} type: cache version: 2 rosdistro-0.8.0/test/files/foo/source-build.yaml000066400000000000000000000007401357352161700217070ustar00rootroot00000000000000%YAML 1.1 # ROS source-build file # see REP 141: http://ros.org/reps/rep-0141.html --- jenkins_job_timeout: 23 jenkins_url: http://farm.example.com:8080 notifications: emails: - admin@example.com maintainers: true targets: _config: apt_mirrors: - http://repo.example.com/ - http://archive.ubuntu.com/ubuntu ubuntu: precise: amd64: i386: quantal: amd64: i386: raring: amd64: i386: type: source-build version: 1 rosdistro-0.8.0/test/files/index_v2.yaml000066400000000000000000000005211357352161700202420ustar00rootroot00000000000000%YAML 1.1 # ROS index file # see REP 141: http://ros.org/reps/rep-0141.html --- distributions: foo: distribution: foo/distribution.yaml distribution_cache: foo/release-cache.yaml doc_builds: [foo/doc-build.yaml] release_builds: [foo/release-build.yaml] source_builds: [foo/source-build.yaml] type: index version: 2 rosdistro-0.8.0/test/files/index_v3.yaml000066400000000000000000000003561357352161700202510ustar00rootroot00000000000000%YAML 1.1 # ROS index file # see REP 143: http://ros.org/reps/rep-0143.html --- distributions: foo: distribution: [foo/distribution.yaml, foo/distribution2.yaml] distribution_cache: foo/release-cache.yaml type: index version: 3 rosdistro-0.8.0/test/files/index_v3_invalid.yaml000066400000000000000000000003561357352161700217570ustar00rootroot00000000000000%YAML 1.1 # ROS index file # see REP 143: http://ros.org/reps/rep-0143.html --- distributions: foo: distribution: [foo/distribution.yaml, foo/distribution3.yaml] distribution_cache: foo/release-cache.yaml type: index version: 3 rosdistro-0.8.0/test/files/index_v4.yaml000066400000000000000000000004521357352161700202470ustar00rootroot00000000000000%YAML 1.1 # ROS index file # see REP 153: http://ros.org/reps/rep-0153.html --- distributions: foo: distribution: [foo/distribution.yaml, foo/distribution2.yaml] distribution_cache: foo/release-cache.yaml distribution_status: active distribution_type: ros1 type: index version: 4 rosdistro-0.8.0/test/github-genmsg-package.xml000066400000000000000000000014611357352161700214150ustar00rootroot00000000000000 genmsg 0.5.11 Standalone Python library for generating ROS message and service data structures for various languages. Dirk Thomas BSD http://www.ros.org/wiki/genmsg https://github.com/ros/genmsg/issues https://github.com/ros/genmsg Troy Straszheim Morten Kjaergaard Ken Conley catkin catkin rosdistro-0.8.0/test/github-tree-data.json000066400000000000000000001333151357352161700205670ustar00rootroot00000000000000{"sha":"81b66fe5eb00043c43894ddeee07e738d9b9712f","url":"https://api.github.com/repos/ros/genmsg/git/trees/81b66fe5eb00043c43894ddeee07e738d9b9712f","tree":[{"path":".gitignore","mode":"100644","type":"blob","sha":"e2545110eb966cdc8dfb79501e72d08b1232f1dd","size":13,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/e2545110eb966cdc8dfb79501e72d08b1232f1dd"},{"path":"CHANGELOG.rst","mode":"100644","type":"blob","sha":"c8ab4e012603078859a428f85afd788df4420cba","size":4253,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/c8ab4e012603078859a428f85afd788df4420cba"},{"path":"CMakeLists.txt","mode":"100644","type":"blob","sha":"a259a059f5d20c091c40da9e03465b98799e97d4","size":569,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/a259a059f5d20c091c40da9e03465b98799e97d4"},{"path":"cmake","mode":"040000","type":"tree","sha":"777dd97894253c404cc5d997ae1e6bcd76a78be8","url":"https://api.github.com/repos/ros/genmsg/git/trees/777dd97894253c404cc5d997ae1e6bcd76a78be8"},{"path":"cmake/genmsg-extras.cmake.em","mode":"100644","type":"blob","sha":"7e2a7efc9a1181486584b4ed85613244b2e7f6f3","size":12101,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/7e2a7efc9a1181486584b4ed85613244b2e7f6f3"},{"path":"cmake/pkg-genmsg.cmake.em","mode":"100644","type":"blob","sha":"7bae5933efd284e53d9d4e77cacca0e355474dd7","size":5670,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/7bae5933efd284e53d9d4e77cacca0e355474dd7"},{"path":"cmake/pkg-genmsg.context.in","mode":"100644","type":"blob","sha":"db3741473ed95f360c971df6afcf0cb7a997dad5","size":420,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/db3741473ed95f360c971df6afcf0cb7a997dad5"},{"path":"cmake/pkg-msg-extras.cmake.in","mode":"100644","type":"blob","sha":"089ac47b36fce3b8d1f58fac13fceb49f2717ecd","size":104,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/089ac47b36fce3b8d1f58fac13fceb49f2717ecd"},{"path":"cmake/pkg-msg-paths.cmake.develspace.in","mode":"100644","type":"blob","sha":"c1024d24e79ba2b6b70df6c5c871b86c0b080d03","size":183,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/c1024d24e79ba2b6b70df6c5c871b86c0b080d03"},{"path":"cmake/pkg-msg-paths.cmake.installspace.in","mode":"100644","type":"blob","sha":"1d35efd80f91a747e89b5f5d8d6e9a933c1da361","size":229,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/1d35efd80f91a747e89b5f5d8d6e9a933c1da361"},{"path":"doc","mode":"040000","type":"tree","sha":"024b633d33bf515374bbd247f619808dbf694ba5","url":"https://api.github.com/repos/ros/genmsg/git/trees/024b633d33bf515374bbd247f619808dbf694ba5"},{"path":"doc/Makefile","mode":"100644","type":"blob","sha":"9b27f15634fd3a453d03ecd6635e3a79d36885ea","size":4784,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/9b27f15634fd3a453d03ecd6635e3a79d36885ea"},{"path":"doc/conf.py","mode":"100644","type":"blob","sha":"b2e6ac44e3f804e4f7d8ec49dde100179b3b940b","size":8704,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/b2e6ac44e3f804e4f7d8ec49dde100179b3b940b"},{"path":"doc/developer.rst","mode":"100644","type":"blob","sha":"21e244d5f8a5ab0be114bd83ddda929fc2487869","size":6870,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/21e244d5f8a5ab0be114bd83ddda929fc2487869"},{"path":"doc/index.rst","mode":"100644","type":"blob","sha":"2137032292edf5dde08c92b637d619270ac98e50","size":651,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/2137032292edf5dde08c92b637d619270ac98e50"},{"path":"doc/python_api.rst","mode":"100644","type":"blob","sha":"4e30598028de897dea9acf6f7df8478049eca233","size":220,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/4e30598028de897dea9acf6f7df8478049eca233"},{"path":"doc/ros.png","mode":"100644","type":"blob","sha":"dca80001867e5b4d1de71bfccb80937b957b2b71","size":6648,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/dca80001867e5b4d1de71bfccb80937b957b2b71"},{"path":"doc/usermacros.rst","mode":"100644","type":"blob","sha":"1e239e083f50101876d68f5a894106c5a5ddfaf4","size":1838,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/1e239e083f50101876d68f5a894106c5a5ddfaf4"},{"path":"package.xml","mode":"100644","type":"blob","sha":"7f0aa79d71f4d8d013f551668bbadc778213fa70","size":784,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/7f0aa79d71f4d8d013f551668bbadc778213fa70"},{"path":"rosdoc.yaml","mode":"100644","type":"blob","sha":"d21d73abcacb58b9b0ff7157d13335d1fc7a70bf","size":43,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/d21d73abcacb58b9b0ff7157d13335d1fc7a70bf"},{"path":"scripts","mode":"040000","type":"tree","sha":"75b1be221bb4c2015d142c3abeffc7c97dae92e7","url":"https://api.github.com/repos/ros/genmsg/git/trees/75b1be221bb4c2015d142c3abeffc7c97dae92e7"},{"path":"scripts/genmsg_check_deps.py","mode":"100755","type":"blob","sha":"2f295a88b4d02755e9cd4a4c07102be36d21ce7a","size":2999,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/2f295a88b4d02755e9cd4a4c07102be36d21ce7a"},{"path":"setup.py","mode":"100755","type":"blob","sha":"5fcae9921ebcfc11423b4d981e8139a46a1e254f","size":215,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/5fcae9921ebcfc11423b4d981e8139a46a1e254f"},{"path":"src","mode":"040000","type":"tree","sha":"76e7b6fe374a7dae3eddaad7087359b020bca873","url":"https://api.github.com/repos/ros/genmsg/git/trees/76e7b6fe374a7dae3eddaad7087359b020bca873"},{"path":"src/genmsg","mode":"040000","type":"tree","sha":"0170c9b64d79af276e5e5c05188943eb48c433f5","url":"https://api.github.com/repos/ros/genmsg/git/trees/0170c9b64d79af276e5e5c05188943eb48c433f5"},{"path":"src/genmsg/__init__.py","mode":"100644","type":"blob","sha":"1c4ba0317b6bce5396fa27da714d9185767ea4c3","size":2116,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/1c4ba0317b6bce5396fa27da714d9185767ea4c3"},{"path":"src/genmsg/base.py","mode":"100644","type":"blob","sha":"b09d89e336a9afc1d8a58362448a54a613158878","size":2414,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/b09d89e336a9afc1d8a58362448a54a613158878"},{"path":"src/genmsg/command_line.py","mode":"100644","type":"blob","sha":"c44be0d5cb8ceb8f2e9af79c13d1fd87c7993095","size":1887,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/c44be0d5cb8ceb8f2e9af79c13d1fd87c7993095"},{"path":"src/genmsg/deps.py","mode":"100644","type":"blob","sha":"372c1df45e25fd6b284d384b1b606ec23f776c95","size":3993,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/372c1df45e25fd6b284d384b1b606ec23f776c95"},{"path":"src/genmsg/gentools.py","mode":"100644","type":"blob","sha":"6f3e23dc678f001a64f856cb7cde8a252788e153","size":6644,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/6f3e23dc678f001a64f856cb7cde8a252788e153"},{"path":"src/genmsg/msg_loader.py","mode":"100644","type":"blob","sha":"12102cec836db0819b6f15e56c6796ad150b44d4","size":20479,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/12102cec836db0819b6f15e56c6796ad150b44d4"},{"path":"src/genmsg/msgs.py","mode":"100644","type":"blob","sha":"1468aa0c17942f5a349d5ed9088add04c133ec6a","size":12253,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/1468aa0c17942f5a349d5ed9088add04c133ec6a"},{"path":"src/genmsg/names.py","mode":"100644","type":"blob","sha":"c0f3ef5d801278608b7be2028332ab6d81f38f11","size":5223,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/c0f3ef5d801278608b7be2028332ab6d81f38f11"},{"path":"src/genmsg/srvs.py","mode":"100644","type":"blob","sha":"faaaddf96ca466ccde60ac18cf18f1dc8ac6d050","size":3017,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/faaaddf96ca466ccde60ac18cf18f1dc8ac6d050"},{"path":"src/genmsg/template_tools.py","mode":"100644","type":"blob","sha":"4478dbcd5c84928e598dc037b7f33f4b9033bfe9","size":9443,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/4478dbcd5c84928e598dc037b7f33f4b9033bfe9"},{"path":"test","mode":"040000","type":"tree","sha":"e23283a12fb074ad2c03334cc4e2897bf3997657","url":"https://api.github.com/repos/ros/genmsg/git/trees/e23283a12fb074ad2c03334cc4e2897bf3997657"},{"path":"test/__init__.py","mode":"100644","type":"blob","sha":"e69de29bb2d1d6434b8b29ae775ad8c2e48c5391","size":0,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/e69de29bb2d1d6434b8b29ae775ad8c2e48c5391"},{"path":"test/files","mode":"040000","type":"tree","sha":"001e4a8b49d28b8091a6e41258ca18457a2cabf2","url":"https://api.github.com/repos/ros/genmsg/git/trees/001e4a8b49d28b8091a6e41258ca18457a2cabf2"},{"path":"test/files/geometry_msgs","mode":"040000","type":"tree","sha":"abc69973379f251b9cf8af4457275d90a8257a12","url":"https://api.github.com/repos/ros/genmsg/git/trees/abc69973379f251b9cf8af4457275d90a8257a12"},{"path":"test/files/geometry_msgs/msg","mode":"040000","type":"tree","sha":"15e1354c67a459e7d0982d9e29a003594c44c627","url":"https://api.github.com/repos/ros/genmsg/git/trees/15e1354c67a459e7d0982d9e29a003594c44c627"},{"path":"test/files/geometry_msgs/msg/Point.msg","mode":"100644","type":"blob","sha":"f1d3a71a853c668f066de795ba5e0f4458f3f1c0","size":84,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/f1d3a71a853c668f066de795ba5e0f4458f3f1c0"},{"path":"test/files/geometry_msgs/msg/Point32.msg","mode":"100644","type":"blob","sha":"52af0a29a13b606b40945c2fd96a6473d0b2067e","size":367,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/52af0a29a13b606b40945c2fd96a6473d0b2067e"},{"path":"test/files/geometry_msgs/msg/PointStamped.msg","mode":"100644","type":"blob","sha":"82c3437946ccaf5c65817a0485cde96992b622dc","size":98,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/82c3437946ccaf5c65817a0485cde96992b622dc"},{"path":"test/files/geometry_msgs/msg/Polygon.msg","mode":"100644","type":"blob","sha":"3399b135f44cc86afe5ba9c2857a0210b157bf4f","size":121,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/3399b135f44cc86afe5ba9c2857a0210b157bf4f"},{"path":"test/files/geometry_msgs/msg/PolygonStamped.msg","mode":"100644","type":"blob","sha":"c9ee413840b3c8bd47d9c41b13a6d68176b29f56","size":104,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/c9ee413840b3c8bd47d9c41b13a6d68176b29f56"},{"path":"test/files/geometry_msgs/msg/Pose.msg","mode":"100644","type":"blob","sha":"b81919c7b256667be00908b866f8bf63404256c6","size":118,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/b81919c7b256667be00908b866f8bf63404256c6"},{"path":"test/files/geometry_msgs/msg/Pose2D.msg","mode":"100644","type":"blob","sha":"e9555b466ac37570adcb69619fa3b3b78a9e602e","size":96,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/e9555b466ac37570adcb69619fa3b3b78a9e602e"},{"path":"test/files/geometry_msgs/msg/PoseArray.msg","mode":"100644","type":"blob","sha":"8a7734b2e954a21042979b0f55866275a2cada6e","size":99,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/8a7734b2e954a21042979b0f55866275a2cada6e"},{"path":"test/files/geometry_msgs/msg/PoseStamped.msg","mode":"100644","type":"blob","sha":"7e3cdc57b7ba5856bce0cb954d20b7a74354bdc2","size":79,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/7e3cdc57b7ba5856bce0cb954d20b7a74354bdc2"},{"path":"test/files/geometry_msgs/msg/PoseWithCovariance.msg","mode":"100644","type":"blob","sha":"86bc45adbb5d7d64e90556ac1f24ca8f725313cd","size":323,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/86bc45adbb5d7d64e90556ac1f24ca8f725313cd"},{"path":"test/files/geometry_msgs/msg/PoseWithCovarianceStamped.msg","mode":"100644","type":"blob","sha":"cdc306b906075b54479aa7a6a0db66f7edbc2f45","size":122,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/cdc306b906075b54479aa7a6a0db66f7edbc2f45"},{"path":"test/files/geometry_msgs/msg/Quaternion.msg","mode":"100644","type":"blob","sha":"9f4fde2bf4c13dc86a95688e4b5254aaec186e2a","size":108,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/9f4fde2bf4c13dc86a95688e4b5254aaec186e2a"},{"path":"test/files/geometry_msgs/msg/QuaternionStamped.msg","mode":"100644","type":"blob","sha":"62c2fdfe992c1a5eef9bf2c3a07aae7f7ad30b8a","size":117,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/62c2fdfe992c1a5eef9bf2c3a07aae7f7ad30b8a"},{"path":"test/files/geometry_msgs/msg/Transform.msg","mode":"100644","type":"blob","sha":"f605c85ea8ec4c4871bdb7d77db6e7011c63e86d","size":118,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/f605c85ea8ec4c4871bdb7d77db6e7011c63e86d"},{"path":"test/files/geometry_msgs/msg/TransformStamped.msg","mode":"100644","type":"blob","sha":"cdcb6e11de990d777717787e35451636debdf70d","size":342,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/cdcb6e11de990d777717787e35451636debdf70d"},{"path":"test/files/geometry_msgs/msg/Twist.msg","mode":"100644","type":"blob","sha":"dc27ca14a7d69f720faff92171456cc71d4fc967","size":117,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/dc27ca14a7d69f720faff92171456cc71d4fc967"},{"path":"test/files/geometry_msgs/msg/TwistStamped.msg","mode":"100644","type":"blob","sha":"53b8253b4251a4c6637ddd85d9937d796558949c","size":82,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/53b8253b4251a4c6637ddd85d9937d796558949c"},{"path":"test/files/geometry_msgs/msg/TwistWithCovariance.msg","mode":"100644","type":"blob","sha":"6d89780154c01faf43175b19363047dcaa9cb73b","size":326,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/6d89780154c01faf43175b19363047dcaa9cb73b"},{"path":"test/files/geometry_msgs/msg/TwistWithCovarianceStamped.msg","mode":"100644","type":"blob","sha":"28667cd3f70c16646228665ad1d3bdc6205593d1","size":123,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/28667cd3f70c16646228665ad1d3bdc6205593d1"},{"path":"test/files/geometry_msgs/msg/Vector3.msg","mode":"100644","type":"blob","sha":"00dd4cbac99e2729865cd00faff2ac482c0794cd","size":73,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/00dd4cbac99e2729865cd00faff2ac482c0794cd"},{"path":"test/files/geometry_msgs/msg/Vector3Stamped.msg","mode":"100644","type":"blob","sha":"e68eb062bebd5bba3cbaf9f33beae5a207f72a51","size":103,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/e68eb062bebd5bba3cbaf9f33beae5a207f72a51"},{"path":"test/files/geometry_msgs/msg/Wrench.msg","mode":"100644","type":"blob","sha":"13a222982943514290874b560d8ac352879ebbf1","size":121,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/13a222982943514290874b560d8ac352879ebbf1"},{"path":"test/files/geometry_msgs/msg/WrenchStamped.msg","mode":"100644","type":"blob","sha":"dad910ed724de005e89e3422ef1ca7cec401e9e4","size":85,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/dad910ed724de005e89e3422ef1ca7cec401e9e4"},{"path":"test/files/invalid","mode":"040000","type":"tree","sha":"0c8b32c318ecd8dc2b6520f7b1273b075dc5f1a3","url":"https://api.github.com/repos/ros/genmsg/git/trees/0c8b32c318ecd8dc2b6520f7b1273b075dc5f1a3"},{"path":"test/files/invalid/msg","mode":"040000","type":"tree","sha":"6ee4cc0d6056661d88c0795a4b24450c61d506a1","url":"https://api.github.com/repos/ros/genmsg/git/trees/6ee4cc0d6056661d88c0795a4b24450c61d506a1"},{"path":"test/files/invalid/msg/BadDepend.msg","mode":"100644","type":"blob","sha":"4725b49036ad244aaf8176ccccdd56f244859982","size":26,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/4725b49036ad244aaf8176ccccdd56f244859982"},{"path":"test/files/invalid/msg/BadLocalDepend.msg","mode":"100644","type":"blob","sha":"cd0b057b3122e1ae92b7277bbb5ce9415602074f","size":17,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/cd0b057b3122e1ae92b7277bbb5ce9415602074f"},{"path":"test/files/rosgraph_msgs","mode":"040000","type":"tree","sha":"ba70dcaa55b90f177dfe9799398944e493e7b000","url":"https://api.github.com/repos/ros/genmsg/git/trees/ba70dcaa55b90f177dfe9799398944e493e7b000"},{"path":"test/files/rosgraph_msgs/msg","mode":"040000","type":"tree","sha":"7280279e75bd0a335db39fb541bad7251dda507b","url":"https://api.github.com/repos/ros/genmsg/git/trees/7280279e75bd0a335db39fb541bad7251dda507b"},{"path":"test/files/rosgraph_msgs/msg/Clock.msg","mode":"100644","type":"blob","sha":"423872fe40f621d516b7cbbca47a800794abf5fd","size":184,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/423872fe40f621d516b7cbbca47a800794abf5fd"},{"path":"test/files/rosgraph_msgs/msg/Log.msg","mode":"100644","type":"blob","sha":"9a9597c2625899fb4cfd1757250dfc0443130f68","size":457,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/9a9597c2625899fb4cfd1757250dfc0443130f68"},{"path":"test/files/sensor_msgs","mode":"040000","type":"tree","sha":"9f349f82eb5becae431795ff5e855c0a38f6d42b","url":"https://api.github.com/repos/ros/genmsg/git/trees/9f349f82eb5becae431795ff5e855c0a38f6d42b"},{"path":"test/files/sensor_msgs/msg","mode":"040000","type":"tree","sha":"2938a899866af5fe8275de8b88b047fb54f72e42","url":"https://api.github.com/repos/ros/genmsg/git/trees/2938a899866af5fe8275de8b88b047fb54f72e42"},{"path":"test/files/sensor_msgs/msg/CameraInfo.msg","mode":"100644","type":"blob","sha":"e498e88d88270ead001def26ae635ad48551e2f6","size":6283,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/e498e88d88270ead001def26ae635ad48551e2f6"},{"path":"test/files/sensor_msgs/msg/ChannelFloat32.msg","mode":"100644","type":"blob","sha":"d2560792898958179806bfc3ec4b98712c4e73a9","size":1008,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/d2560792898958179806bfc3ec4b98712c4e73a9"},{"path":"test/files/sensor_msgs/msg/CompressedImage.msg","mode":"100644","type":"blob","sha":"d9e8a64651e447278ae34622849b7dd8846d134f","size":641,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/d9e8a64651e447278ae34622849b7dd8846d134f"},{"path":"test/files/sensor_msgs/msg/Image.msg","mode":"100644","type":"blob","sha":"37029bc0709d1d911b25d7360bfacdea92974045","size":1349,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/37029bc0709d1d911b25d7360bfacdea92974045"},{"path":"test/files/sensor_msgs/msg/Imu.msg","mode":"100644","type":"blob","sha":"7ef82c1fa8b7ac219d372033a743dc711407d231","size":1195,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/7ef82c1fa8b7ac219d372033a743dc711407d231"},{"path":"test/files/sensor_msgs/msg/JointState.msg","mode":"100644","type":"blob","sha":"f67f4bcf214cbf187cf5ba557f34fcbfb6966cf2","size":995,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/f67f4bcf214cbf187cf5ba557f34fcbfb6966cf2"},{"path":"test/files/sensor_msgs/msg/Joy.msg","mode":"100644","type":"blob","sha":"e51cb43a792dad9b1f9c47f463e5cc1614042f89","size":286,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/e51cb43a792dad9b1f9c47f463e5cc1614042f89"},{"path":"test/files/sensor_msgs/msg/JoyFeedback.msg","mode":"100644","type":"blob","sha":"9ecedab75320de59e62ca6fdf210e6825417c91d","size":413,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/9ecedab75320de59e62ca6fdf210e6825417c91d"},{"path":"test/files/sensor_msgs/msg/JoyFeedbackArray.msg","mode":"100644","type":"blob","sha":"9bb72b79b5a7bed2af52ebac83a458497a42a1b0","size":83,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/9bb72b79b5a7bed2af52ebac83a458497a42a1b0"},{"path":"test/files/sensor_msgs/msg/LaserScan.msg","mode":"100644","type":"blob","sha":"910751b8b8c5d5b96f8db07964c7865a5cc20009","size":1519,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/910751b8b8c5d5b96f8db07964c7865a5cc20009"},{"path":"test/files/sensor_msgs/msg/NavSatFix.msg","mode":"100644","type":"blob","sha":"6307f80e9f531b983f871317c122b7a5aacc3d1e","size":1233,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/6307f80e9f531b983f871317c122b7a5aacc3d1e"},{"path":"test/files/sensor_msgs/msg/NavSatStatus.msg","mode":"100644","type":"blob","sha":"4fce76f23d23c6e7f2ceea2f4c34014da8021d34","size":753,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/4fce76f23d23c6e7f2ceea2f4c34014da8021d34"},{"path":"test/files/sensor_msgs/msg/PointCloud.msg","mode":"100644","type":"blob","sha":"a0eac50c6deb978502181896f4a99eef90f960a7","size":553,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/a0eac50c6deb978502181896f4a99eef90f960a7"},{"path":"test/files/sensor_msgs/msg/PointCloud2.msg","mode":"100644","type":"blob","sha":"69a9302a2a10d22b52f0bc3344d98ad27b784f13","size":1039,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/69a9302a2a10d22b52f0bc3344d98ad27b784f13"},{"path":"test/files/sensor_msgs/msg/PointField.msg","mode":"100644","type":"blob","sha":"fb9ff5453f772608066466358c77b742f8d84174","size":425,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/fb9ff5453f772608066466358c77b742f8d84174"},{"path":"test/files/sensor_msgs/msg/Range.msg","mode":"100644","type":"blob","sha":"669fee667d4928853ba468a2adb1c4b83cfa837d","size":1251,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/669fee667d4928853ba468a2adb1c4b83cfa837d"},{"path":"test/files/sensor_msgs/msg/RegionOfInterest.msg","mode":"100644","type":"blob","sha":"c423dcf88952a13df86abd36c81746ff85ee502b","size":872,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/c423dcf88952a13df86abd36c81746ff85ee502b"},{"path":"test/files/std_msgs","mode":"040000","type":"tree","sha":"aac3aee6a7f5e81cb2b78814188995b5bcbfeaf0","url":"https://api.github.com/repos/ros/genmsg/git/trees/aac3aee6a7f5e81cb2b78814188995b5bcbfeaf0"},{"path":"test/files/std_msgs/msg","mode":"040000","type":"tree","sha":"e59d26597f6cc33b8c919c25af1bfc47ef9fd727","url":"https://api.github.com/repos/ros/genmsg/git/trees/e59d26597f6cc33b8c919c25af1bfc47ef9fd727"},{"path":"test/files/std_msgs/msg/Bool.msg","mode":"100644","type":"blob","sha":"f7cabb94fc04ac5f83ca8f219357b439f29d002f","size":9,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/f7cabb94fc04ac5f83ca8f219357b439f29d002f"},{"path":"test/files/std_msgs/msg/ColorRGBA.msg","mode":"100644","type":"blob","sha":"182dbc8349abec122d95436cb840906503f569f2","size":40,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/182dbc8349abec122d95436cb840906503f569f2"},{"path":"test/files/std_msgs/msg/Duration.msg","mode":"100644","type":"blob","sha":"f13931ec8a7937ca624ff91af7f861559b5fc3fe","size":14,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/f13931ec8a7937ca624ff91af7f861559b5fc3fe"},{"path":"test/files/std_msgs/msg/Empty.msg","mode":"100644","type":"blob","sha":"e69de29bb2d1d6434b8b29ae775ad8c2e48c5391","size":0,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/e69de29bb2d1d6434b8b29ae775ad8c2e48c5391"},{"path":"test/files/std_msgs/msg/Float32.msg","mode":"100644","type":"blob","sha":"e89740534bd9c0344c18709de0c29667620295bd","size":12,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/e89740534bd9c0344c18709de0c29667620295bd"},{"path":"test/files/std_msgs/msg/Float32MultiArray.msg","mode":"100644","type":"blob","sha":"915830846dd023a111abd8ad2831d982b9c85a82","size":210,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/915830846dd023a111abd8ad2831d982b9c85a82"},{"path":"test/files/std_msgs/msg/Float64.msg","mode":"100644","type":"blob","sha":"cd09d39b8caedf067b9548d62ecab3c73b6ecace","size":12,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/cd09d39b8caedf067b9548d62ecab3c73b6ecace"},{"path":"test/files/std_msgs/msg/Float64MultiArray.msg","mode":"100644","type":"blob","sha":"0a13b928fd70d116defc17ec0acc09a6296b57ff","size":210,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/0a13b928fd70d116defc17ec0acc09a6296b57ff"},{"path":"test/files/std_msgs/msg/Header.msg","mode":"100644","type":"blob","sha":"b2f34f6f1d15f22149dae16e5e6bbf190a89a0d8","size":500,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/b2f34f6f1d15f22149dae16e5e6bbf190a89a0d8"},{"path":"test/files/std_msgs/msg/Int16.msg","mode":"100644","type":"blob","sha":"c4389faf706f189e64bc576af0f7788f06d16c86","size":11,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/c4389faf706f189e64bc576af0f7788f06d16c86"},{"path":"test/files/std_msgs/msg/Int16MultiArray.msg","mode":"100644","type":"blob","sha":"d2ddea1d1d6a69a15cb17e434900a1afbadaac89","size":210,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/d2ddea1d1d6a69a15cb17e434900a1afbadaac89"},{"path":"test/files/std_msgs/msg/Int32.msg","mode":"100644","type":"blob","sha":"0ecfe35f5f480f463e0b26e696c4f0e858aba06c","size":10,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/0ecfe35f5f480f463e0b26e696c4f0e858aba06c"},{"path":"test/files/std_msgs/msg/Int32MultiArray.msg","mode":"100644","type":"blob","sha":"af60abda3a697bac5e596b23b04038414258188a","size":210,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/af60abda3a697bac5e596b23b04038414258188a"},{"path":"test/files/std_msgs/msg/Int64.msg","mode":"100644","type":"blob","sha":"6961e00f52989d8e03f54e0a0e0333ae470e6508","size":10,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/6961e00f52989d8e03f54e0a0e0333ae470e6508"},{"path":"test/files/std_msgs/msg/Int64MultiArray.msg","mode":"100644","type":"blob","sha":"f4f35e171b316dacbb0eb3a80e20885977171ebd","size":210,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/f4f35e171b316dacbb0eb3a80e20885977171ebd"},{"path":"test/files/std_msgs/msg/Int8.msg","mode":"100644","type":"blob","sha":"1e42e554feea25175f15af74433d802e86ed0180","size":10,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/1e42e554feea25175f15af74433d802e86ed0180"},{"path":"test/files/std_msgs/msg/Int8MultiArray.msg","mode":"100644","type":"blob","sha":"a59a37259e5e97c8dbee0072f4e6c282d7fc8fd3","size":210,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/a59a37259e5e97c8dbee0072f4e6c282d7fc8fd3"},{"path":"test/files/std_msgs/msg/MultiArrayDimension.msg","mode":"100644","type":"blob","sha":"08240462c4315969a5a8cde9292683c51865a5d3","size":141,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/08240462c4315969a5a8cde9292683c51865a5d3"},{"path":"test/files/std_msgs/msg/MultiArrayLayout.msg","mode":"100644","type":"blob","sha":"5437f8542af613c0058e380c27ab59cb5ebb7df0","size":907,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/5437f8542af613c0058e380c27ab59cb5ebb7df0"},{"path":"test/files/std_msgs/msg/String.msg","mode":"100644","type":"blob","sha":"ae721739e8fa7035347d3fed3cca1b137e670c97","size":12,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/ae721739e8fa7035347d3fed3cca1b137e670c97"},{"path":"test/files/std_msgs/msg/Time.msg","mode":"100644","type":"blob","sha":"7f8f721711fbbc620fa7f6b58a9f89d5667281be","size":10,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/7f8f721711fbbc620fa7f6b58a9f89d5667281be"},{"path":"test/files/std_msgs/msg/UInt16.msg","mode":"100644","type":"blob","sha":"87d0c44eb59dca29f419aaa77801b4fbc278f9f6","size":12,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/87d0c44eb59dca29f419aaa77801b4fbc278f9f6"},{"path":"test/files/std_msgs/msg/UInt16MultiArray.msg","mode":"100644","type":"blob","sha":"f38970b656cf1160e292f9effc8f5d8c3281a12b","size":210,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/f38970b656cf1160e292f9effc8f5d8c3281a12b"},{"path":"test/files/std_msgs/msg/UInt32.msg","mode":"100644","type":"blob","sha":"b6c696b421e4a4c89c7f1420fbaa15af83913093","size":11,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/b6c696b421e4a4c89c7f1420fbaa15af83913093"},{"path":"test/files/std_msgs/msg/UInt32MultiArray.msg","mode":"100644","type":"blob","sha":"b2bb0771f0208bc3c45210a918d689d5a24b53a7","size":210,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/b2bb0771f0208bc3c45210a918d689d5a24b53a7"},{"path":"test/files/std_msgs/msg/UInt64.msg","mode":"100644","type":"blob","sha":"2eb1afad37e320a366f7b0296fb207569a30db47","size":11,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/2eb1afad37e320a366f7b0296fb207569a30db47"},{"path":"test/files/std_msgs/msg/UInt64MultiArray.msg","mode":"100644","type":"blob","sha":"30d0cd92854159d4cc3fa5e996763cc08e9dcdf9","size":210,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/30d0cd92854159d4cc3fa5e996763cc08e9dcdf9"},{"path":"test/files/std_msgs/msg/UInt8.msg","mode":"100644","type":"blob","sha":"5eefd870db82c99cf7d62e7ccff1824c114bd462","size":11,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/5eefd870db82c99cf7d62e7ccff1824c114bd462"},{"path":"test/files/std_msgs/msg/UInt8MultiArray.msg","mode":"100644","type":"blob","sha":"31f7d6a213995f216f4d124f1d6402852d1572b2","size":210,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/31f7d6a213995f216f4d124f1d6402852d1572b2"},{"path":"test/files/std_srvs","mode":"040000","type":"tree","sha":"6d91522aca605e31e723bfe7351af9c7865d08d9","url":"https://api.github.com/repos/ros/genmsg/git/trees/6d91522aca605e31e723bfe7351af9c7865d08d9"},{"path":"test/files/std_srvs/srv","mode":"040000","type":"tree","sha":"6e131065f744a9b73a4026216e27c94b42ba4eea","url":"https://api.github.com/repos/ros/genmsg/git/trees/6e131065f744a9b73a4026216e27c94b42ba4eea"},{"path":"test/files/std_srvs/srv/Empty.srv","mode":"100644","type":"blob","sha":"73b314ff7c704c18889cf90fdc024716c634adb6","size":3,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/73b314ff7c704c18889cf90fdc024716c634adb6"},{"path":"test/files/test_ros","mode":"040000","type":"tree","sha":"2c6651eb1894b92e24084972ec3f7621e2f5c3ad","url":"https://api.github.com/repos/ros/genmsg/git/trees/2c6651eb1894b92e24084972ec3f7621e2f5c3ad"},{"path":"test/files/test_ros/msg","mode":"040000","type":"tree","sha":"e9efd6bba02faca0a15840f42d6cde16e2aefd55","url":"https://api.github.com/repos/ros/genmsg/git/trees/e9efd6bba02faca0a15840f42d6cde16e2aefd55"},{"path":"test/files/test_ros/msg/Bad.msg","mode":"100644","type":"blob","sha":"d9bbac9c4b62f296238cfb1a78d2ef4d427d8f46","size":29,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/d9bbac9c4b62f296238cfb1a78d2ef4d427d8f46"},{"path":"test/files/test_ros/msg/TestString.msg","mode":"100644","type":"blob","sha":"4ab04385050da20743d887191f80a17361d0f4c3","size":185,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/4ab04385050da20743d887191f80a17361d0f4c3"},{"path":"test/files/test_ros/srv","mode":"040000","type":"tree","sha":"b3ca71cb6b0a088de34a1b2cac9bfcbc2bc15216","url":"https://api.github.com/repos/ros/genmsg/git/trees/b3ca71cb6b0a088de34a1b2cac9bfcbc2bc15216"},{"path":"test/files/test_ros/srv/AddTwoInts.srv","mode":"100644","type":"blob","sha":"3a68808ee591a3623cbf5e553eed28bac5233be8","size":30,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/3a68808ee591a3623cbf5e553eed28bac5233be8"},{"path":"test/files/test_ros/srv/GetPoseStamped.srv","mode":"100644","type":"blob","sha":"d462907f82e732cd4b2b851adfd9defae79149c8","size":35,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/d462907f82e732cd4b2b851adfd9defae79149c8"},{"path":"test/md5tests","mode":"040000","type":"tree","sha":"6e79e84cbc487758dbbefeeda9cbca7d722d12ab","url":"https://api.github.com/repos/ros/genmsg/git/trees/6e79e84cbc487758dbbefeeda9cbca7d722d12ab"},{"path":"test/md5tests/different","mode":"040000","type":"tree","sha":"4fa0305374c6b08b3e2346c8932c850b05a455f5","url":"https://api.github.com/repos/ros/genmsg/git/trees/4fa0305374c6b08b3e2346c8932c850b05a455f5"},{"path":"test/md5tests/different/constants1.txt","mode":"100644","type":"blob","sha":"bbdcc07babe5b2dc72843b6a16a2bac9b7ea9163","size":10,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/bbdcc07babe5b2dc72843b6a16a2bac9b7ea9163"},{"path":"test/md5tests/different/constants2.txt","mode":"100644","type":"blob","sha":"163e43089adf522185fdacaaceb86dbcc3c84283","size":10,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/163e43089adf522185fdacaaceb86dbcc3c84283"},{"path":"test/md5tests/different/constants3.txt","mode":"100644","type":"blob","sha":"33c5b1db88ff05489608736a43d34645b9fda15b","size":11,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/33c5b1db88ff05489608736a43d34645b9fda15b"},{"path":"test/md5tests/different/constantsB1.txt","mode":"100644","type":"blob","sha":"3839b46f5aa44b9b2546e9519c02c59b4373f6a1","size":46,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/3839b46f5aa44b9b2546e9519c02c59b4373f6a1"},{"path":"test/md5tests/different/constantsB2.txt","mode":"100644","type":"blob","sha":"2901a264e4768acb82c5ef2061d27ea353b689b1","size":45,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/2901a264e4768acb82c5ef2061d27ea353b689b1"},{"path":"test/md5tests/different/fields1.txt","mode":"100644","type":"blob","sha":"c763ffa5ae0294dd0f82ea11e423f7416cc87344","size":24,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/c763ffa5ae0294dd0f82ea11e423f7416cc87344"},{"path":"test/md5tests/different/fields2.txt","mode":"100644","type":"blob","sha":"035777c38592342c76c1e46cd84c6efdbca4cc95","size":16,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/035777c38592342c76c1e46cd84c6efdbca4cc95"},{"path":"test/md5tests/different/fields3.txt","mode":"100644","type":"blob","sha":"aabefcb1a0947bc5f9adcec545dd6282fe7428c0","size":32,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/aabefcb1a0947bc5f9adcec545dd6282fe7428c0"},{"path":"test/md5tests/different/fields4.txt","mode":"100644","type":"blob","sha":"518e2d210bf697ed2ff35d9445c44f3e78ce1ad7","size":25,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/518e2d210bf697ed2ff35d9445c44f3e78ce1ad7"},{"path":"test/md5tests/different/fields5.txt","mode":"100644","type":"blob","sha":"9a0abc3d4ad4d0d0ffb8ea1956ebe22c5a8ee704","size":25,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/9a0abc3d4ad4d0d0ffb8ea1956ebe22c5a8ee704"},{"path":"test/md5tests/md5text","mode":"040000","type":"tree","sha":"82f6d93ad1bc5c792084415d9eaa53e195ed371b","url":"https://api.github.com/repos/ros/genmsg/git/trees/82f6d93ad1bc5c792084415d9eaa53e195ed371b"},{"path":"test/md5tests/md5text/constant1.txt","mode":"100644","type":"blob","sha":"8e09574bc4a20f26dc1d004f670b2f547c40fa8c","size":15,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/8e09574bc4a20f26dc1d004f670b2f547c40fa8c"},{"path":"test/md5tests/md5text/constant2.txt","mode":"100644","type":"blob","sha":"fefbb5721a0b25c5cb70fe2bf7c9145fef9b6f1b","size":17,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/fefbb5721a0b25c5cb70fe2bf7c9145fef9b6f1b"},{"path":"test/md5tests/md5text/constant3.txt","mode":"100644","type":"blob","sha":"ac5f6f972149f5053e93ce08418bc7eb5d92ebd5","size":51,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/ac5f6f972149f5053e93ce08418bc7eb5d92ebd5"},{"path":"test/md5tests/md5text/constantB1.txt","mode":"100644","type":"blob","sha":"2db0afd64fd9aa8bf6a1e6396dd789f0397b790d","size":17,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/2db0afd64fd9aa8bf6a1e6396dd789f0397b790d"},{"path":"test/md5tests/md5text/constantB2.txt","mode":"100644","type":"blob","sha":"a6bd453df21b6cf267d7c35e38f2edf584e0d113","size":27,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/a6bd453df21b6cf267d7c35e38f2edf584e0d113"},{"path":"test/md5tests/md5text/constantC1.txt","mode":"100644","type":"blob","sha":"f0b3d0a25cab1493ba10082bd004dcf2f74f742f","size":83,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/f0b3d0a25cab1493ba10082bd004dcf2f74f742f"},{"path":"test/md5tests/md5text/constantC2.txt","mode":"100644","type":"blob","sha":"ac0753b7ff0092f9b42e6357392351ed1ed68dde","size":100,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/ac0753b7ff0092f9b42e6357392351ed1ed68dde"},{"path":"test/md5tests/md5text/embed1.txt","mode":"100644","type":"blob","sha":"4eda895981fbc222c2e5aa9d06603c096ec969b6","size":37,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/4eda895981fbc222c2e5aa9d06603c096ec969b6"},{"path":"test/md5tests/md5text/embed2.txt","mode":"100644","type":"blob","sha":"6cfe1f5760174f4a0a22f27de7b437a5bf6073c8","size":22,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/6cfe1f5760174f4a0a22f27de7b437a5bf6073c8"},{"path":"test/md5tests/md5text/embed3.txt","mode":"100644","type":"blob","sha":"5562b1d303073e972cae93921c52f7c5f23ee585","size":50,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/5562b1d303073e972cae93921c52f7c5f23ee585"},{"path":"test/md5tests/md5text/embed4.txt","mode":"100644","type":"blob","sha":"a9d30dd70242263acdd237bfb8c1ec254efe2abc","size":60,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/a9d30dd70242263acdd237bfb8c1ec254efe2abc"},{"path":"test/md5tests/md5text/empty1.txt","mode":"100644","type":"blob","sha":"e69de29bb2d1d6434b8b29ae775ad8c2e48c5391","size":0,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/e69de29bb2d1d6434b8b29ae775ad8c2e48c5391"},{"path":"test/md5tests/md5text/empty2.txt","mode":"100644","type":"blob","sha":"8d1c8b69c3fce7bea45c73efd06983e3c419a92f","size":2,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/8d1c8b69c3fce7bea45c73efd06983e3c419a92f"},{"path":"test/md5tests/md5text/empty3.txt","mode":"100644","type":"blob","sha":"324811884a926f66f66ae364387d3568981e8f2f","size":19,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/324811884a926f66f66ae364387d3568981e8f2f"},{"path":"test/md5tests/md5text/empty4.txt","mode":"100644","type":"blob","sha":"1b9cb525f45ab6d9bd4346e9fad1130024aa2389","size":38,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/1b9cb525f45ab6d9bd4346e9fad1130024aa2389"},{"path":"test/md5tests/md5text/field1.txt","mode":"100644","type":"blob","sha":"b0369cb9b571ac55970ef296bd579c7aa6d7e63f","size":12,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/b0369cb9b571ac55970ef296bd579c7aa6d7e63f"},{"path":"test/md5tests/md5text/field2.txt","mode":"100644","type":"blob","sha":"6699ede22096fa4db958abedeedc071a2ab1beeb","size":28,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/6699ede22096fa4db958abedeedc071a2ab1beeb"},{"path":"test/md5tests/md5text/field3.txt","mode":"100644","type":"blob","sha":"cc58824bf8dad9af4ca1d59f2c3e7ddb738b143a","size":27,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/cc58824bf8dad9af4ca1d59f2c3e7ddb738b143a"},{"path":"test/md5tests/md5text/field4.txt","mode":"100644","type":"blob","sha":"40a5023ed2c4a2526cad6d8472e384ac6d90fe01","size":17,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/40a5023ed2c4a2526cad6d8472e384ac6d90fe01"},{"path":"test/md5tests/md5text/field5.txt","mode":"100644","type":"blob","sha":"d30c030c13dc5afb01485ff02fcaddc3b41f6b23","size":46,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/d30c030c13dc5afb01485ff02fcaddc3b41f6b23"},{"path":"test/md5tests/md5text/multi1.txt","mode":"100644","type":"blob","sha":"409be8d58a609237fc8faea7e58a8ed86613687e","size":118,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/409be8d58a609237fc8faea7e58a8ed86613687e"},{"path":"test/md5tests/md5text/multi2.txt","mode":"100644","type":"blob","sha":"8adf8ee332f4c0179fc8a35082a6e6e970df5b61","size":222,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/8adf8ee332f4c0179fc8a35082a6e6e970df5b61"},{"path":"test/md5tests/md5text/multi3.txt","mode":"100644","type":"blob","sha":"19e8a78041c5f82110ef20bffc09c35869455b0f","size":63,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/19e8a78041c5f82110ef20bffc09c35869455b0f"},{"path":"test/md5tests/md5text/multi4.txt","mode":"100644","type":"blob","sha":"30e806468830e277f228834825597089cbcbb874","size":266,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/30e806468830e277f228834825597089cbcbb874"},{"path":"test/md5tests/md5text/multi5.txt","mode":"100644","type":"blob","sha":"9b289463095c0f29b42c45915773f2a609dca12c","size":100,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/9b289463095c0f29b42c45915773f2a609dca12c"},{"path":"test/md5tests/same","mode":"040000","type":"tree","sha":"2591f8a6c7d524898ad20888e50a83ef5acb4eb3","url":"https://api.github.com/repos/ros/genmsg/git/trees/2591f8a6c7d524898ad20888e50a83ef5acb4eb3"},{"path":"test/md5tests/same/constant1.txt","mode":"100644","type":"blob","sha":"8e09574bc4a20f26dc1d004f670b2f547c40fa8c","size":15,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/8e09574bc4a20f26dc1d004f670b2f547c40fa8c"},{"path":"test/md5tests/same/constant2.txt","mode":"100644","type":"blob","sha":"fefbb5721a0b25c5cb70fe2bf7c9145fef9b6f1b","size":17,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/fefbb5721a0b25c5cb70fe2bf7c9145fef9b6f1b"},{"path":"test/md5tests/same/constant3.txt","mode":"100644","type":"blob","sha":"ac5f6f972149f5053e93ce08418bc7eb5d92ebd5","size":51,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/ac5f6f972149f5053e93ce08418bc7eb5d92ebd5"},{"path":"test/md5tests/same/constantB1.txt","mode":"100644","type":"blob","sha":"2db0afd64fd9aa8bf6a1e6396dd789f0397b790d","size":17,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/2db0afd64fd9aa8bf6a1e6396dd789f0397b790d"},{"path":"test/md5tests/same/constantB2.txt","mode":"100644","type":"blob","sha":"a6bd453df21b6cf267d7c35e38f2edf584e0d113","size":27,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/a6bd453df21b6cf267d7c35e38f2edf584e0d113"},{"path":"test/md5tests/same/constantC1.txt","mode":"100644","type":"blob","sha":"f0b3d0a25cab1493ba10082bd004dcf2f74f742f","size":83,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/f0b3d0a25cab1493ba10082bd004dcf2f74f742f"},{"path":"test/md5tests/same/constantC2.txt","mode":"100644","type":"blob","sha":"ac0753b7ff0092f9b42e6357392351ed1ed68dde","size":100,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/ac0753b7ff0092f9b42e6357392351ed1ed68dde"},{"path":"test/md5tests/same/embed1.txt","mode":"100644","type":"blob","sha":"6cfe1f5760174f4a0a22f27de7b437a5bf6073c8","size":22,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/6cfe1f5760174f4a0a22f27de7b437a5bf6073c8"},{"path":"test/md5tests/same/embed2.txt","mode":"100644","type":"blob","sha":"c9ddc1e1e5a318f4aaa390df4ac693a0de95823a","size":8,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/c9ddc1e1e5a318f4aaa390df4ac693a0de95823a"},{"path":"test/md5tests/same/embed3.txt","mode":"100644","type":"blob","sha":"5562b1d303073e972cae93921c52f7c5f23ee585","size":50,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/5562b1d303073e972cae93921c52f7c5f23ee585"},{"path":"test/md5tests/same/embed4.txt","mode":"100644","type":"blob","sha":"a9d30dd70242263acdd237bfb8c1ec254efe2abc","size":60,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/a9d30dd70242263acdd237bfb8c1ec254efe2abc"},{"path":"test/md5tests/same/empty1.txt","mode":"100644","type":"blob","sha":"e69de29bb2d1d6434b8b29ae775ad8c2e48c5391","size":0,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/e69de29bb2d1d6434b8b29ae775ad8c2e48c5391"},{"path":"test/md5tests/same/empty2.txt","mode":"100644","type":"blob","sha":"8d1c8b69c3fce7bea45c73efd06983e3c419a92f","size":2,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/8d1c8b69c3fce7bea45c73efd06983e3c419a92f"},{"path":"test/md5tests/same/empty3.txt","mode":"100644","type":"blob","sha":"324811884a926f66f66ae364387d3568981e8f2f","size":19,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/324811884a926f66f66ae364387d3568981e8f2f"},{"path":"test/md5tests/same/empty4.txt","mode":"100644","type":"blob","sha":"1b9cb525f45ab6d9bd4346e9fad1130024aa2389","size":38,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/1b9cb525f45ab6d9bd4346e9fad1130024aa2389"},{"path":"test/md5tests/same/field1.txt","mode":"100644","type":"blob","sha":"b0369cb9b571ac55970ef296bd579c7aa6d7e63f","size":12,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/b0369cb9b571ac55970ef296bd579c7aa6d7e63f"},{"path":"test/md5tests/same/field2.txt","mode":"100644","type":"blob","sha":"6699ede22096fa4db958abedeedc071a2ab1beeb","size":28,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/6699ede22096fa4db958abedeedc071a2ab1beeb"},{"path":"test/md5tests/same/field3.txt","mode":"100644","type":"blob","sha":"cc58824bf8dad9af4ca1d59f2c3e7ddb738b143a","size":27,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/cc58824bf8dad9af4ca1d59f2c3e7ddb738b143a"},{"path":"test/md5tests/same/field4.txt","mode":"100644","type":"blob","sha":"40a5023ed2c4a2526cad6d8472e384ac6d90fe01","size":17,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/40a5023ed2c4a2526cad6d8472e384ac6d90fe01"},{"path":"test/md5tests/same/field5.txt","mode":"100644","type":"blob","sha":"d30c030c13dc5afb01485ff02fcaddc3b41f6b23","size":46,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/d30c030c13dc5afb01485ff02fcaddc3b41f6b23"},{"path":"test/md5tests/same/multi1.txt","mode":"100644","type":"blob","sha":"4fd310a2275b2e259a7a6d7dfba7614c3de1958d","size":90,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/4fd310a2275b2e259a7a6d7dfba7614c3de1958d"},{"path":"test/md5tests/same/multi2.txt","mode":"100644","type":"blob","sha":"8adf8ee332f4c0179fc8a35082a6e6e970df5b61","size":222,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/8adf8ee332f4c0179fc8a35082a6e6e970df5b61"},{"path":"test/md5tests/same/multi3.txt","mode":"100644","type":"blob","sha":"19e8a78041c5f82110ef20bffc09c35869455b0f","size":63,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/19e8a78041c5f82110ef20bffc09c35869455b0f"},{"path":"test/md5tests/same/multi4.txt","mode":"100644","type":"blob","sha":"30e806468830e277f228834825597089cbcbb874","size":266,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/30e806468830e277f228834825597089cbcbb874"},{"path":"test/md5tests/same/multi5.txt","mode":"100644","type":"blob","sha":"9b289463095c0f29b42c45915773f2a609dca12c","size":100,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/9b289463095c0f29b42c45915773f2a609dca12c"},{"path":"test/test_genmsg_base.py","mode":"100644","type":"blob","sha":"aff6883e4aa03d26976bcf1626a3e654f75979c5","size":347,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/aff6883e4aa03d26976bcf1626a3e654f75979c5"},{"path":"test/test_genmsg_command_line.py","mode":"100644","type":"blob","sha":"8f9ff025a4a0ed373383e1b420163d97a7b7d719","size":1937,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/8f9ff025a4a0ed373383e1b420163d97a7b7d719"},{"path":"test/test_genmsg_gentools.py","mode":"100644","type":"blob","sha":"8797d823ceeefcbdacfc26423492667d462e778d","size":9526,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/8797d823ceeefcbdacfc26423492667d462e778d"},{"path":"test/test_genmsg_msg_loader.py","mode":"100644","type":"blob","sha":"74dc782f12acd249986c44838a981a2a0f67e40b","size":29225,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/74dc782f12acd249986c44838a981a2a0f67e40b"},{"path":"test/test_genmsg_msgs.py","mode":"100644","type":"blob","sha":"8573d91ff15923332a4db0cfb4926a478a28e950","size":11646,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/8573d91ff15923332a4db0cfb4926a478a28e950"},{"path":"test/test_genmsg_names.py","mode":"100644","type":"blob","sha":"0608e6e386116f174de5a917c902d1e6e5cb4f3e","size":4540,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/0608e6e386116f174de5a917c902d1e6e5cb4f3e"},{"path":"test/test_genmsg_srvs.py","mode":"100644","type":"blob","sha":"b1c6023b33f7b0b23b2ca3297bfb1d2f79319a84","size":3233,"url":"https://api.github.com/repos/ros/genmsg/git/blobs/b1c6023b33f7b0b23b2ca3297bfb1d2f79319a84"}],"truncated":false}rosdistro-0.8.0/test/test_cache.py000066400000000000000000000004631357352161700172170ustar00rootroot00000000000000import os from rosdistro import get_distribution_cache, get_index FILES_DIR = os.path.normpath(os.path.join(os.path.dirname(os.path.abspath(__file__)), 'files')) def test_get_release_cache(): url = 'file://' + FILES_DIR + '/index_v2.yaml' i = get_index(url) get_distribution_cache(i, 'foo') rosdistro-0.8.0/test/test_distribution.py000066400000000000000000000024721357352161700206750ustar00rootroot00000000000000import os from rosdistro import get_distribution_file, get_distribution_files, get_index from rosdistro.distribution_file import DistributionFile from rosdistro.loader import load_url import yaml FILES_DIR = os.path.normpath(os.path.join(os.path.dirname(os.path.abspath(__file__)), 'files')) def test_distribution_file(): url = 'file://' + FILES_DIR + '/foo/distribution.yaml' yaml_str = load_url(url) data = yaml.load(yaml_str) dist_file = DistributionFile('foo', data) _validate_dist_file(dist_file) def test_get_distribution_file(): url = 'file://' + FILES_DIR + '/index_v2.yaml' i = get_index(url) dist_file = get_distribution_file(i, 'foo') _validate_dist_file(dist_file) dist_files = get_distribution_files(i, 'foo') assert len(dist_files) == 1 def _validate_dist_file(dist_file): assert('bar_repo' in dist_file.repositories) repo = dist_file.repositories['bar_repo'] assert repo.release_repository.package_names == ['bar_repo'] assert 'bar_repo' in dist_file.release_packages assert'baz-repo' in dist_file.repositories repo = dist_file.repositories['baz-repo'] assert set(repo.release_repository.package_names) == set(['baz_pkg1', 'baz_pkg2']) assert 'baz_pkg1' in dist_file.release_packages assert 'baz_pkg2' in dist_file.release_packages rosdistro-0.8.0/test/test_doc.py000066400000000000000000000021231357352161700167140ustar00rootroot00000000000000import os from rosdistro import get_doc_file, get_index from rosdistro.doc_file import DocFile from rosdistro.loader import load_url import yaml FILES_DIR = os.path.normpath(os.path.join(os.path.dirname(os.path.abspath(__file__)), 'files')) def test_doc_file(): url = 'file://' + FILES_DIR + '/foo/distribution.yaml' yaml_str = load_url(url) data = yaml.load(yaml_str) doc_file = DocFile('foo', data) _validate_doc_file(doc_file) def test_get_doc_file(): url = 'file://' + FILES_DIR + '/index_v2.yaml' i = get_index(url) doc_file = get_doc_file(i, 'foo') _validate_doc_file(doc_file) def _validate_doc_file(doc_file): assert(set(['bar_repo', 'baz-repo']) == set(doc_file.repositories.keys())) repo = doc_file.repositories['bar_repo'] assert(repo.type == 'git') assert(repo.url == 'https://github.com/example-test/bar_repo.git') assert(repo.version == 'master') repo = doc_file.repositories['baz-repo'] assert(repo.type == 'hg') assert(repo.url == 'https://bitbucket.org/baz-test/baz-repo') assert(repo.version == 'default') rosdistro-0.8.0/test/test_doc_build.py000066400000000000000000000012601357352161700200740ustar00rootroot00000000000000import os from rosdistro import get_doc_build_files, get_index from rosdistro.doc_build_file import DocBuildFile from rosdistro.loader import load_url import yaml FILES_DIR = os.path.normpath(os.path.join(os.path.dirname(os.path.abspath(__file__)), 'files')) def test_doc_build_file(): url = 'file://' + FILES_DIR + '/foo/doc-build.yaml' yaml_str = load_url(url) data = yaml.load(yaml_str) DocBuildFile('foo', data) def test_get_doc_build_files(): url = 'file://' + FILES_DIR + '/index_v2.yaml' i = get_index(url) files = get_doc_build_files(i, 'foo') assert len(files) == 1 build_file = files[0] assert build_file.jenkins_job_timeout == 23 rosdistro-0.8.0/test/test_index.py000066400000000000000000000057261357352161700172720ustar00rootroot00000000000000import os from rosdistro import get_distribution_file from rosdistro import get_distribution_files from rosdistro import get_index from rosdistro import get_index_url FILES_DIR = os.path.normpath(os.path.join(os.path.dirname(os.path.abspath(__file__)), 'files')) def test_get_index_url(): get_index_url() def test_get_index_v2(): url = 'file://' + FILES_DIR + '/index_v2.yaml' i = get_index(url) assert len(i.distributions.keys()) == 1 assert 'foo' in i.distributions.keys() assert 'distribution_status' not in i.distributions['foo'] assert 'distribution_type' not in i.distributions['foo'] def test_get_index_v3(): url = 'file://' + FILES_DIR + '/index_v3.yaml' i = get_index(url) assert len(i.distributions.keys()) == 1 assert 'foo' in i.distributions.keys() assert 'distribution_status' not in i.distributions['foo'] assert 'distribution_type' not in i.distributions['foo'] dist_files = get_distribution_files(i, 'foo') assert len(dist_files) == 2 get_distribution_file(i, 'foo') def test_get_index_v3_invalid(): url = 'file://' + FILES_DIR + '/index_v3_invalid.yaml' i = get_index(url) dist_files = get_distribution_files(i, 'foo') assert len(dist_files) == 2 try: get_distribution_file(i, 'foo') assert False except AssertionError: pass def test_get_index_v4(): url = 'file://' + FILES_DIR + '/index_v4.yaml' i = get_index(url) assert len(i.distributions.keys()) == 1 assert 'foo' in i.distributions.keys() assert i.distributions['foo']['distribution_status'] == 'active' assert i.distributions['foo']['distribution_type'] == 'ros1' dist_files = get_distribution_files(i, 'foo') assert len(dist_files) == 2 get_distribution_file(i, 'foo') def test_get_index_from_http_with_query_parameters(): import subprocess import sys import time url = 'http://localhost:9876/index_v3.yaml?raw&at=master' # start a http server and wait if sys.version_info < (3, 0, 0): proc = subprocess.Popen([sys.executable, '-m', 'SimpleHTTPServer', '9876'], cwd=FILES_DIR) else: proc = subprocess.Popen([sys.executable, '-m', 'http.server', '9876'], cwd=FILES_DIR) time.sleep(0.5) try: i = get_index(url) assert len(i.distributions.keys()) == 1 assert 'foo' in i.distributions.keys() # test if every url has the same queries for key, dist_urls in i.distributions['foo'].items(): if key in ('distribution_status', 'distribution_type'): continue if not isinstance(dist_urls, list): dist_urls = [dist_urls] for dist_url in dist_urls: assert dist_url.endswith('?raw&at=master') dist_files = get_distribution_files(i, 'foo') assert len(dist_files) == 2 get_distribution_file(i, 'foo') finally: proc.terminate() rosdistro-0.8.0/test/test_manifest_providers.py000066400000000000000000000122311357352161700220530ustar00rootroot00000000000000# -*- coding: utf-8 -*- import mock import rosdistro.manifest_provider.github import rosdistro.vcs from rosdistro.manifest_provider.bitbucket import bitbucket_manifest_provider from rosdistro.manifest_provider.cache import CachedManifestProvider, sanitize_xml from rosdistro.manifest_provider.git import git_manifest_provider, git_source_manifest_provider from rosdistro.release_repository_specification import ReleaseRepositorySpecification from rosdistro.source_repository_specification import SourceRepositorySpecification def test_bitbucket(): assert '' in bitbucket_manifest_provider('indigo', _rospeex_release_repo(), 'rospeex_msgs') def test_cached(): class FakeDistributionCache(object): def __init__(self): self.release_package_xmls = {} dc = FakeDistributionCache() cache = CachedManifestProvider(dc, [rosdistro.manifest_provider.github.github_manifest_provider]) assert '' in cache('melodic', _genmsg_release_repo(), 'genmsg') def test_git(): assert '' in git_manifest_provider('melodic', _genmsg_release_repo(), 'genmsg') def test_git_legacy(): rosdistro.vcs.Git._client_version = '1.7.0' assert '' in git_manifest_provider('melodic', _genmsg_release_repo(), 'genmsg') rosdistro.vcs.Git._client_version = None def test_github(): assert '' in rosdistro.manifest_provider.github.github_manifest_provider('melodic', _genmsg_release_repo(), 'genmsg') def test_git_source(): repo_cache = git_source_manifest_provider(_genmsg_source_repo()) # This hash corresponds to the 0.5.11 tag. assert repo_cache.ref() == 'a189fc78558e7276df59d2961cfe4f8b4de08a8b' package_path, package_xml = repo_cache['genmsg'] assert '' == package_path assert '0.5.11' in package_xml # mock_get_url_contents is used to mock out the '_get_url_contents' method in # the rosdistro.manifest_provider.github module. Instead of going out to github # to get data (which can get rate-limited in Travis), it instead pulls a canned # example from some local files. def mock_get_url_contents(req): import re # For python3, look for the 'str' type; for Python 2, the 'unicode' type try: text_type = unicode except NameError: text_type = str # The urlopen() function from urllib or urllib2 takes either a string or a # urllib.Request object in; determine the URL in either case. if isinstance(req, text_type): haystack = req else: haystack = req.get_full_url() # Now see if the URL ends with 'package.xml'. If it does, open up the file # that has the canned package.xml data we have for genmsg. Otherwise, # return the canned JSON tree data that github would have returned. # In both cases, store the file-like object as a module property so that we # can properly close it during 'unmock_urlopen'. if re.search('.*package.xml$', haystack) is not None: fname = 'test/github-genmsg-package.xml' else: fname = 'test/github-tree-data.json' with open(fname, 'r') as infp: data = infp.read() return data @mock.patch('rosdistro.manifest_provider.github._get_url_contents', mock_get_url_contents) def test_github_source(): repo_cache = rosdistro.manifest_provider.github.github_source_manifest_provider(_genmsg_source_repo()) # This hash corresponds to the 0.5.7 tag. assert repo_cache.ref() == '81b66fe5eb00043c43894ddeee07e738d9b9712f' package_path, package_xml = repo_cache['genmsg'] assert '' == package_path assert '0.5.11' in package_xml def test_git_source_multi(): repo_cache = git_source_manifest_provider(_ros_source_repo()) assert repo_cache.ref() package_path, package_xml = repo_cache['roslib'] assert package_path == 'core/roslib' def test_sanitize(): assert 'abc' in sanitize_xml('abc') assert 'ab c' in sanitize_xml(' ab c ') # This unicode check should be valid on both Python 2 and 3. assert 'français' in sanitize_xml(' français ') # subsequent parse calls will collapse empty tags, therefore sanitize should do the same assert '' in sanitize_xml(' ') def _genmsg_release_repo(): return ReleaseRepositorySpecification('genmsg', { 'url': 'https://github.com/ros-gbp/genmsg-release.git', 'tags': {'release': 'release/melodic/{package}/{version}'}, 'version': '0.5.11-0' }) def _genmsg_source_repo(): return SourceRepositorySpecification('genmsg', { 'url': 'https://github.com/ros/genmsg.git', 'version': '0.5.11' }) def _ros_source_repo(): return SourceRepositorySpecification('ros', { 'url': 'https://github.com/ros/ros.git', 'version': 'kinetic-devel' }) def _rospeex_release_repo(): return ReleaseRepositorySpecification('rospeex', { 'packages': ['rospeex', 'rospeex_msgs'], 'tags': {'release': 'release/indigo/{package}/{version}'}, 'url': 'https://bitbucket.org/rospeex/rospeex-release.git', 'version': '2.14.7-0' }) rosdistro-0.8.0/test/test_release.py000066400000000000000000000021371357352161700175740ustar00rootroot00000000000000import os from rosdistro import get_index, get_release_file from rosdistro.loader import load_url from rosdistro.release_file import ReleaseFile import yaml FILES_DIR = os.path.normpath(os.path.join(os.path.dirname(os.path.abspath(__file__)), 'files')) def test_release_file(): url = 'file://' + FILES_DIR + '/foo/distribution.yaml' yaml_str = load_url(url) data = yaml.load(yaml_str) rel_file = ReleaseFile('foo', data) _validate_rel_file(rel_file) def test_get_release_file(): url = 'file://' + FILES_DIR + '/index_v2.yaml' i = get_index(url) rel_file = get_release_file(i, 'foo') _validate_rel_file(rel_file) def _validate_rel_file(rel_file): assert('bar_repo' in rel_file.repositories) repo = rel_file.repositories['bar_repo'] assert repo.package_names == ['bar_repo'] assert 'bar_repo' in rel_file.packages assert'baz-repo' in rel_file.repositories repo = rel_file.repositories['baz-repo'] assert set(repo.package_names) == set(['baz_pkg1', 'baz_pkg2']) assert 'baz_pkg1' in rel_file.packages assert 'baz_pkg2' in rel_file.packages rosdistro-0.8.0/test/test_release_build.py000066400000000000000000000034641357352161700207570ustar00rootroot00000000000000import os from rosdistro import get_index, get_release, get_release_build_files, get_release_builds from rosdistro.loader import load_url from rosdistro.release_build_file import ReleaseBuildFile import yaml FILES_DIR = os.path.normpath(os.path.join(os.path.dirname(os.path.abspath(__file__)), 'files')) def test_release_build_file(): url = 'file://' + FILES_DIR + '/foo/release-build.yaml' yaml_str = load_url(url) data = yaml.load(yaml_str) ReleaseBuildFile('foo', data) def test_get_release_build_files(): url = 'file://' + FILES_DIR + '/index_v2.yaml' i = get_index(url) get_release_build_files(i, 'foo') def test_get_release_builds(): url = 'file://' + FILES_DIR + '/index_v2.yaml' i = get_index(url) d = get_release(i, 'foo') builds = get_release_builds(i, d) assert len(builds) == 1 build = builds[0] assert build.jenkins_sourcedeb_job_timeout == 5 assert build.jenkins_binarydeb_job_timeout == 42 os_names = build.get_target_os_names() assert set(os_names) == set(['ubuntu']) os_code_names = build.get_target_os_code_names('ubuntu') assert set(os_code_names) == set(['precise', 'quantal', 'raring']) arches = build.get_target_arches('ubuntu', 'precise') assert set(arches) == set(['amd64', 'i386']) c = build.get_target_configuration() assert len(c.keys()) == 2 assert set(c.keys()) == set(['apt_target_repository', 'foo']) assert c['apt_target_repository'] == 'http://repo.example.com/' assert c['foo'] == 'bar' c = build.get_target_configuration('ubuntu', 'precise') assert 'foo' in c.keys() assert c['foo'] == 'bar' assert 'ping' in c.keys() assert c['ping'] == 'pong' c = build.get_target_configuration('ubuntu', 'precise', 'amd64') assert 'foo' in c.keys() assert c['foo'] == 'baz' rosdistro-0.8.0/test/test_repository_specification.py000066400000000000000000000016741357352161700233000ustar00rootroot00000000000000from rosdistro.repository_specification import RepositorySpecification def test_repository_specification(): data = {'type': 'git', 'url': 'https://github.com/ros/catkin.git'} r = RepositorySpecification("test", data) assert r.get_data() == data assert r.version is None assert r.get_url_parts() == ('github.com', 'ros/catkin') r.url = 'http://github.com/ros/catkin' assert r.get_url_parts() == ('github.com', 'ros/catkin') r.url = 'ssh://example.com/a/b/c.git' assert r.get_url_parts() == ('example.com', 'a/b/c') r.url = 'git://example.com/a/b/c/d.git' assert r.get_url_parts() == ('example.com', 'a/b/c/d') r.url = 'git@example.com:a/b/c/d/e.git' assert r.get_url_parts() == ('example.com', 'a/b/c/d/e') r.url = 'https://1234567890abcdeABCDE1234567890abcdeABCDE@example.com:a/b/c/d/e.git' assert r.get_url_parts() == ('1234567890abcdeABCDE1234567890abcdeABCDE@example.com', 'a/b/c/d/e') rosdistro-0.8.0/test/test_source.py000066400000000000000000000021501357352161700174470ustar00rootroot00000000000000import os from rosdistro import get_index, get_source_file from rosdistro.loader import load_url from rosdistro.source_file import SourceFile import yaml FILES_DIR = os.path.normpath(os.path.join(os.path.dirname(os.path.abspath(__file__)), 'files')) def test_source_file(): url = 'file://' + FILES_DIR + '/foo/distribution.yaml' yaml_str = load_url(url) data = yaml.load(yaml_str) src_file = SourceFile('foo', data) _validate_src_file(src_file) def test_get_source_file(): url = 'file://' + FILES_DIR + '/index_v2.yaml' i = get_index(url) src_file = get_source_file(i, 'foo') _validate_src_file(src_file) def _validate_src_file(src_file): assert(set(['bar_repo', 'baz-repo']) == set(src_file.repositories.keys())) repo = src_file.repositories['bar_repo'] assert(repo.type == 'git') assert(repo.url == 'https://github.com/example-test/bar_repo.git') assert(repo.version == 'master') repo = src_file.repositories['baz-repo'] assert(repo.type == 'hg') assert(repo.url == 'https://bitbucket.org/baz-test/baz-repo') assert(repo.version == 'default') rosdistro-0.8.0/test/test_source_build.py000066400000000000000000000013101357352161700206230ustar00rootroot00000000000000import os from rosdistro import get_index, get_source_build_files from rosdistro.loader import load_url from rosdistro.source_build_file import SourceBuildFile import yaml FILES_DIR = os.path.normpath(os.path.join(os.path.dirname(os.path.abspath(__file__)), 'files')) def test_source_build_file(): url = 'file://' + FILES_DIR + '/foo/source-build.yaml' yaml_str = load_url(url) data = yaml.load(yaml_str) SourceBuildFile('foo', data) def test_get_source_build_files(): url = 'file://' + FILES_DIR + '/index_v2.yaml' i = get_index(url) files = get_source_build_files(i, 'foo') assert len(files) == 1 build_file = files[0] assert build_file.jenkins_job_timeout == 23 rosdistro-0.8.0/test/test_verify.py000066400000000000000000000007131357352161700174560ustar00rootroot00000000000000import os from rosdistro.verify import verify_files_identical, verify_files_parsable FILES_DIR = os.path.normpath(os.path.join(os.path.dirname(os.path.abspath(__file__)), 'files')) def test_verify_files_parsable(): index_url = 'file://' + FILES_DIR + '/index_v2.yaml' assert verify_files_parsable(index_url) def test_verify_files_identical(): index_url = 'file://' + FILES_DIR + '/index_v2.yaml' assert verify_files_identical(index_url) rosdistro-0.8.0/test/test_writer.py000066400000000000000000000024261357352161700174710ustar00rootroot00000000000000import difflib import os from rosdistro import get_distribution_file, get_index from rosdistro.writer import yaml_from_distribution_file FILES_DIR = os.path.normpath(os.path.join(os.path.dirname(os.path.abspath(__file__)), 'files')) def get_diff(expected, actual): udiff = difflib.unified_diff(expected.splitlines(), actual.splitlines(), fromfile='expected', tofile='actual') udiff_raw = '' for line in udiff: if line.startswith('@@'): udiff_raw += line if line.startswith('+'): if not line.startswith('+++'): line += '\n' udiff_raw += line if line.startswith('-'): if not line.startswith('---'): line += '\n' udiff_raw += line if line.startswith(' '): line += '\n' udiff_raw += line return '\n' + udiff_raw def test_verify_files_parsable(): url = 'file://' + FILES_DIR + '/index_v2.yaml' index = get_index(url) distribution_file = get_distribution_file(index, 'foo') data = yaml_from_distribution_file(distribution_file) with open(os.path.join(FILES_DIR, 'foo', 'distribution.yaml'), 'r') as f: expected = f.read() assert data == expected, get_diff(expected, data)