pax_global_header00006660000000000000000000000064126017135470014520gustar00rootroot0000000000000052 comment=dc8f83e73438e2ffacc0847b5d8ea1df4c144488 ros-rosdep-0.11.4/000077500000000000000000000000001260171354700137005ustar00rootroot00000000000000ros-rosdep-0.11.4/.gitignore000066400000000000000000000001641260171354700156710ustar00rootroot00000000000000*.orig *.swp *.pyc *.DS_Store *~ *.log .coverage nosetests.xml target build deb_dist dist src/rosdep.egg-info nose* ros-rosdep-0.11.4/.travis.yml000066400000000000000000000006761260171354700160220ustar00rootroot00000000000000language: python python: - "2.6" - "2.7" - "3.4" # command to install dependencies install: # develop seems to be required by travis since 02/2013 - pip install PyYAML argparse rospkg vcstools catkin_pkg python-dateutil distribute rosdistro - python setup.py build develop - pip install nose coverage # command to run tests script: - nosetests --with-coverage --cover-package=rosdep2 --with-xunit test notifications: email: false ros-rosdep-0.11.4/CHANGELOG.rst000066400000000000000000000012151260171354700157200ustar00rootroot000000000000000.11.4 (2015-09-25) ------------------- - Fix bug in `pip` package detection code. 0.11.3 (2015-09-24) ------------------- - Added an option to print out only apt and pip installable packages as commands. - Added warning when neither the ``ROS_DISTRO`` environment variable is set nor the ``--rosdistro`` option is used. - Fixed a bug related to group id resolution. - Switched to using DNF instead of YUM for Fedora 22+. - Fixed a bug where pip packages were not detected for older versions of ``pip``. - Fixed a bug where dependencies of packages were gotten from the wrong ``package.xml`` when that package was being overlaid with local packages. ros-rosdep-0.11.4/LICENSE000066400000000000000000000030551260171354700147100ustar00rootroot00000000000000# Copyright (c) 2013, 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 the 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. ros-rosdep-0.11.4/Makefile000066400000000000000000000010041260171354700153330ustar00rootroot00000000000000.PHONY: all setup clean_dist distro clean install testsetup test NAME='rosdep' VERSION=`python setup.py -V` 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 rosdep tests" test: testsetup nosetests --with-coverage --cover-package=rosdep2 --with-xunit test ros-rosdep-0.11.4/README.md000066400000000000000000000010011260171354700151470ustar00rootroot00000000000000rosdep ------ rosdep is a command-line tool for installing system dependencies. For *end-users*, rosdep helps you install system dependencies for software that you are building from source. For *developers*, rosdep simplifies the problem of installing system dependencies on different platforms. Instead of having to figure out which debian package on Ubuntu Oneiric contains Boost, you can just specify a dependency on 'boost'. [rosdep Users/Developers Guide](http://docs.ros.org/independent/api/rosdep/html/) ros-rosdep-0.11.4/doc/000077500000000000000000000000001260171354700144455ustar00rootroot00000000000000ros-rosdep-0.11.4/doc/Makefile000066400000000000000000000113171260171354700161100ustar00rootroot00000000000000# Makefile for Sphinx documentation # # You can set these variables from the command line. SPHINXOPTS = SPHINXBUILD = sphinx-build PAPER = BUILDDIR = _build # Internal variables. PAPEROPT_a4 = -D latex_paper_size=a4 PAPEROPT_letter = -D latex_paper_size=letter ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . .PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest help: @echo "Please use \`make ' where is one of" @echo " html to make standalone HTML files" @echo " dirhtml to make HTML files named index.html in directories" @echo " singlehtml to make a single large HTML file" @echo " pickle to make pickle files" @echo " json to make JSON files" @echo " htmlhelp to make HTML files and a HTML help project" @echo " qthelp to make HTML files and a qthelp project" @echo " devhelp to make HTML files and a Devhelp project" @echo " epub to make an epub" @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" @echo " latexpdf to make LaTeX files and run them through pdflatex" @echo " text to make text files" @echo " man to make manual pages" @echo " changes to make an overview of all changed/added/deprecated items" @echo " linkcheck to check all external links for integrity" @echo " doctest to run all doctests embedded in the documentation (if enabled)" clean: -rm -rf $(BUILDDIR)/* html: $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." dirhtml: $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." singlehtml: $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml @echo @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." pickle: $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle @echo @echo "Build finished; now you can process the pickle files." json: $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json @echo @echo "Build finished; now you can process the JSON files." htmlhelp: $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp @echo @echo "Build finished; now you can run HTML Help Workshop with the" \ ".hhp project file in $(BUILDDIR)/htmlhelp." qthelp: $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp @echo @echo "Build finished; now you can run "qcollectiongenerator" with the" \ ".qhcp project file in $(BUILDDIR)/qthelp, like this:" @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/rosdep.qhcp" @echo "To view the help file:" @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/rosdep.qhc" devhelp: $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp @echo @echo "Build finished." @echo "To view the help file:" @echo "# mkdir -p $$HOME/.local/share/devhelp/rosdep" @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/rosdep" @echo "# devhelp" epub: $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub @echo @echo "Build finished. The epub file is in $(BUILDDIR)/epub." latex: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." @echo "Run \`make' in that directory to run these through (pdf)latex" \ "(use \`make latexpdf' here to do that automatically)." latexpdf: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo "Running LaTeX files through pdflatex..." make -C $(BUILDDIR)/latex all-pdf @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." text: $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text @echo @echo "Build finished. The text files are in $(BUILDDIR)/text." man: $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man @echo @echo "Build finished. The manual pages are in $(BUILDDIR)/man." changes: $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes @echo @echo "The overview file is in $(BUILDDIR)/changes." linkcheck: $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck @echo @echo "Link check complete; look for any errors in the above output " \ "or in $(BUILDDIR)/linkcheck/output.txt." doctest: $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest @echo "Testing of doctests in the sources finished, look at the " \ "results in $(BUILDDIR)/doctest/output.txt." upload: html # set write permission for group so that everybody can overwrite existing files on the webserver chmod -R g+w _build/html/ scp -pr _build/html/ rosbot@ros.osuosl.org:/home/rosbot/docs/independent/api/rosdep ros-rosdep-0.11.4/doc/_templates/000077500000000000000000000000001260171354700166025ustar00rootroot00000000000000ros-rosdep-0.11.4/doc/_templates/index.html000066400000000000000000000043351260171354700206040ustar00rootroot00000000000000{% extends "layout.html" %} {% set title = 'ROS packages' %} {% block body %}

Welcome

rosdep is a command-line tool for installing system dependencies. For *end-users*, rosdep helps you install system dependencies for software that you are building from source. For *developers*, rosdep simplifies the problem of installing system dependencies on different platforms. Instead of having to figure out which debian package on Ubuntu Oneiric contains Boost, you can just specify a dependency on 'boost'. rosdep is supported on a variety of platforms/package managers:

Documentation

{% endblock %} ros-rosdep-0.11.4/doc/commands.rst000066400000000000000000000071441260171354700170060ustar00rootroot00000000000000rosdep command reference ======================== .. _rosdep_usage: Synopsis -------- **rosdep** <*command*> [*options*] [*args*] Description ----------- The **rosdep** command helps you install external dependencies in an OS-independent manner. For example, what Debian packages do you need in order to get the OpenGL headers on Ubuntu? How about OS X? Fedora? rosdep can answer this question for your platform and install the necessary package(s). Run ``rosdep -h`` or ``rosdep -h`` to access the built-in tool documentation. Commands -------- **check ...** Check if the dependencies of ROS package(s) have been met. **db** Display the local rosdep database. **init** Initialize /etc/ros/rosdep/sources.list.d/ configuration. May require sudo. **install ...** Install dependencies for specified ROS packages. **keys ...** List the rosdep keys that the ROS packages depend on. **resolve ...** Resolve to system dependencies **update** Update the local rosdep database based on the rosdep sources. **what-needs ...** Print a list of packages that declare a rosdep on (at least one of) **where-defined ...** Print a list of YAML files that declare a rosdep on (at least one of) Options ------- **--os=OS_NAME:OS_VERSION** Override OS name and version (colon-separated), e.g. ubuntu:lucid **-c SOURCES_CACHE_DIR, --sources-cache-dir=SOURCES_CACHE_DIR** Override default sources cache directory (local rosdep database). **-a, --all** Select all ROS packages. Only valid for commands that take as arguments. **-h, --help** Show usage information **-v, --verbose** Enable verbose output **--version** Print version and exit. **-q** Suppress output except for errors **-n** Do not consider implicit/recursive dependencies. Only valid with ``keys``, ``check``, and ``install`` commands. **-i, --ignore-packages-from-source, --ignore-src** Affects the ``check`` and ``install`` verbs. If specified then rosdep will not install keys that are found to be catkin packages anywhere in the ROS_PACKAGE_PATH or in any of the directories given by the ``--from-paths`` option. **--skip-keys=SKIP_KEYS** Affects the ``check`` and ``install`` verbs. The specified rosdep keys will be ignored, i.e. not resolved and not installed. The option can be supplied multiple times. A space separated list of rosdep keys can also be passed as a string. A more permanent solution to locally ignore a rosdep key is creating a local rosdep rule with an empty list of packages (include it in ``/etc/ros/rosdep/sources.list.d/`` before the defaults). **--from-paths** Affects the ``check``, ``keys``, and ``install`` verbs. If specified the arugments to those verbs will be considered paths to be searched, acting on all catkin packages found there in. **--rosdistro=ROS_DISTRO** Explicitly sets the ROS distro to use, overriding the normal method of detecting the ROS distro using the ROS_DISTRO environment variable. **--as-root=INSTALLER_KEY:** Override whether sudo is used for a specific installer, e.g. ``--as-root pip:false`` or ``--as-root "pip:no homebrew:yes"``. Can be specified multiple times. Install Options --------------- **--reinstall** (re)install all dependencies, even if already installed **-y, --default-yes** Tell the package manager to default to y or fail when installing **-s, --simulate** Simulate install **-r** Continue installing despite errors. **-R** Install implicit/recursive dependencies. ros-rosdep-0.11.4/doc/conf.py000066400000000000000000000164541260171354700157560ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # rosdep documentation build configuration file, created by # sphinx-quickstart on Mon Sep 12 17:13:25 2011. # # This file is execfile()d with the current directory set to its containing dir. # # Note that not all possible configuration values are present in this # autogenerated file. # # All configuration values have a default; values that are commented out # serve to show the default. import sys, os import sys sys.path.insert(0, '../src') import catkin_sphinx from rosdep2 import __version__ # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. #sys.path.insert(0, os.path.abspath('.')) # -- General configuration ----------------------------------------------------- # If your documentation needs a minimal Sphinx version, state it here. #needs_sphinx = '1.0' # Add any Sphinx extension module names here, as strings. They can be extensions # coming with Sphinx (named 'sphinx.ext.*') or your custom ones. extensions = ['sphinx.ext.autodoc', 'sphinx.ext.intersphinx', 'sphinx.ext.coverage', 'sphinx.ext.viewcode'] # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] # The suffix of source filenames. source_suffix = '.rst' # The encoding of source files. #source_encoding = 'utf-8-sig' # The master toctree document. master_doc = 'contents' # General information about the project. project = u'rosdep' copyright = u'2011, Willow Garage' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the # built documents. # # The short X.Y version. version = __version__ # The full version, including alpha/beta/rc tags. release = __version__ # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. #language = None # There are two options for replacing |today|: either, you set today to some # non-false value, then it is used: #today = '' # Else, today_fmt is used as the format for a strftime call. #today_fmt = '%B %d, %Y' # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. exclude_patterns = ['_build'] # The reST default role (used for this markup: `text`) to use for all documents. #default_role = None # If true, '()' will be appended to :func: etc. cross-reference text. #add_function_parentheses = True # If true, the current module name will be prepended to all description # unit titles (such as .. function::). #add_module_names = True # If true, sectionauthor and moduleauthor directives will be shown in the # output. They are ignored by default. #show_authors = False # The name of the Pygments (syntax highlighting) style to use. pygments_style = 'sphinx' # A list of ignored prefixes for module index sorting. #modindex_common_prefix = [] # -- Options for HTML output --------------------------------------------------- # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. html_theme_path = [os.path.join(os.path.dirname(catkin_sphinx.__file__), 'theme')] html_theme = 'ros-theme' html_logo = 'ros.png' # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the # documentation. #html_theme_options = {} # Add any paths that contain custom themes here, relative to this directory. #html_theme_path = [] # The name for this set of Sphinx documents. If None, it defaults to # " v documentation". #html_title = None # A shorter title for the navigation bar. Default is the same as html_title. #html_short_title = None # The name of an image file (relative to this directory) to place at the top # of the sidebar. #html_logo = None # The name of an image file (within the static path) to use as favicon of the # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 # pixels large. #html_favicon = None # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". html_static_path = ['_static'] # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, # using the given strftime format. #html_last_updated_fmt = '%b %d, %Y' # If true, SmartyPants will be used to convert quotes and dashes to # typographically correct entities. #html_use_smartypants = True # Custom sidebar templates, maps document names to template names. #html_sidebars = {} # Additional templates that should be rendered to pages, maps page names to # template names. #html_additional_pages = {} html_additional_pages = {'index': 'index.html'} # If false, no module index is generated. #html_domain_indices = True # If false, no index is generated. #html_use_index = True # If true, the index is split into individual pages for each letter. #html_split_index = False # If true, links to the reST sources are added to the pages. #html_show_sourcelink = True # If true, "Created using Sphinx" is shown in the HTML footer. Default is True. #html_show_sphinx = True # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. #html_show_copyright = True # If true, an OpenSearch description file will be output, and all pages will # contain a tag referring to it. The value of this option must be the # base URL from which the finished HTML is served. #html_use_opensearch = '' # This is the file name suffix for HTML files (e.g. ".xhtml"). #html_file_suffix = None # Output file base name for HTML help builder. htmlhelp_basename = 'rosdepdoc' # -- Options for LaTeX output -------------------------------------------------- # The paper size ('letter' or 'a4'). #latex_paper_size = 'letter' # The font size ('10pt', '11pt' or '12pt'). #latex_font_size = '10pt' # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, author, documentclass [howto/manual]). latex_documents = [ ('rosdep.tex', u'rosdep Documentation', u'Tully Foote, Ken Conley', 'manual'), ] # The name of an image file (relative to this directory) to place at the top of # the title page. #latex_logo = None # For "manual" documents, if this is true, then toplevel headings are parts, # not chapters. #latex_use_parts = False # If true, show page references after internal links. #latex_show_pagerefs = False # If true, show URL addresses after external links. #latex_show_urls = False # Additional stuff for the LaTeX preamble. #latex_preamble = '' # Documents to append as an appendix to all manuals. #latex_appendices = [] # If false, no module index is generated. #latex_domain_indices = True # -- Options for manual page output -------------------------------------------- # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). man_pages = [ ('man/rosdep', 'rosdep', u'rosdep command', [u'Tully Foote, Ken Conley'], 1) ] # Example configuration for intersphinx: refer to the Python standard library. intersphinx_mapping = {'http://docs.python.org/': None} ros-rosdep-0.11.4/doc/contents.rst000066400000000000000000000002501260171354700170310ustar00rootroot00000000000000Contents ======== .. toctree:: :maxdepth: 2 overview commands contributing_rules rosdep_yaml_format sources_list developers_guide rosdep2_api ros-rosdep-0.11.4/doc/contributing_rules.rst000066400000000000000000000054461260171354700211310ustar00rootroot00000000000000Contributing rosdep rules ========================= In order to contribute rosdep rules, you should first make sure that you are familiar with the :ref:`rosdep.yaml format `. Summary ''''''' There are several steps to contributing rosdep rules. You will create a copy of the database on GitHub, point your own rosdep to use it, make some changes, and then ask that they be included back in the main database. In short: 1. Fork https://github.com/ros/rosdistro 2. Update your ``/etc/ros/rosdep/sources.list.d`` to use this fork 3. Modify your fork to have new rules 4. Test your changes 5. Send a pull request to have your changes included in the main database Fork the rosdistro GitHub repository ------------------------------------ The main rosdep database is stored in files in the "rosdistro" repository in the "ros" project on GitHub: `https://github.com/ros/rosdistro `_ Start by forking this repository so you have your own copy of the database to work with. Next, you'll point your local rosdep to use this database instead. Point your sources.list.d at your forked repository --------------------------------------------------- The default sources list for rosdep uses the following files:: yaml https://github.com/ros/rosdistro/raw/master/rosdep/base.yaml yaml https://github.com/ros/rosdistro/raw/master/rosdep/python.yaml yaml https://github.com/ros/rosdistro/raw/master/rosdep/osx-homebrew.yaml osx Create a new file in ``/etc/ros/rosdep/sources.list.d/`` that points at your forked repository instead. The filename should use a lower number so it is processed first. Now that your rosdep is using the new database, you're ready to make and test your changes. Make your changes to your forked repository ------------------------------------------- The repository contains the following files: - ``rosdep/osx-homebrew.yaml``: Rules for OS X Homebrew - ``rosdep/python.yaml``: Python-specific dependencies - ``rosdep/base.yaml``: Everything else Edit the appropriate file(s) for your change, i.e., if you are contributing a Homebrew rule, only edit ``osx-homebrew.yaml``, if you are contributing a rule for a Python library, only edit ``python.yaml``, and, otherwise, put your rule in ``base.yaml``. Make sure that your rules work ------------------------------ Update your local index:: rosdep update Test your new rules:: rosdep resolve Test with different OS rules:: rosdep resolve --os=OS_NAME:OS_VERSION Submit a pull request with your updated rules --------------------------------------------- Use GitHub's pull request mechanism to request that your updates get included in the main databases. After your request has been accepted, you can undo your changes to ``/etc/ros/rosdep/sources.list.d``. ros-rosdep-0.11.4/doc/developers_guide.rst000066400000000000000000000123251260171354700205270ustar00rootroot00000000000000.. _dev_guide: Developer's Guide ================= Python API reference -------------------- In progress, please see :ref:`Python API `. REP 114: rospkg standalone library ---------------------------------- The rosdep library is being developed using the ROS REP process. It is necessary to be familiar with these REPs in order to make sure that rosdep continues to follow the relevant specifications. - `REP 111: Multiple Package Manager Support for Rosdep `_. - `REP 112: Source Package Manager for Rosdep `_. - `REP 125: rosdep 2 `_. Bug reports and feature requests -------------------------------- - `Submit a bug report `_ - `Submit a feature request `_ Getting the code ---------------- The rosdep codebase is hosted on GitHub. To get started contributing patches, please create a fork: https://github.com/ros-infrastructure/rosdep Supporting a new OS/package manager ----------------------------------- Adding new platforms to rosdep can be separated into two steps: adding support for a new package manager, and adding support for a new OS. NOTE: There are numerous examples in :mod:`rosdep2.platforms` that you can follow. Declaring a new OS '''''''''''''''''' Adding support for a new OS is fairly straightforward: you just have to provide rosdep2 the keys that are associated with your OS and the keys of the installers that your OS supports. Implementations must provide a ``register_platforms(context)`` call which sets up the keys used for the OS and package managers. The registration only sets up associated keys -- it does not specify the implementation. OS keys should be pulled from ``rospkg.os_detect`` if they are available. This example registers the ``gentoo`` OS and adds support for the ``equery`` and ``source`` package managers. It then sets the default package manager to ``equery``:: from rospkg.os_detect import OS_GENTOO def register_platforms(context): context.add_os_installer_key(OS_GENTOO, EQUERY_INSTALLER) context.add_os_installer_key(OS_GENTOO, SOURCE_INSTALLER) context.set_default_os_installer_key(OS_GENTOO, EQUERY_INSTALLER) Declaring a new installer ''''''''''''''''''''''''' A new installer is registered with the system using a ``register_installers(context)`` call. This call aqssociates the installer key with an implementation. This example declares that ``pip`` is implemented using the ``PipInstaller()`` class. We also declare the ``PIP_INSTALLER`` variable so that other code can use it symbolically.:: PIP_INSTALLER = 'pip' def register_installers(context): context.set_installer(PIP_INSTALLER, PipInstaller()) Most installers are implemented using the the :class:`PackageManagerInstaller` API. The following is the implementation of the ``PipInstaller``:: class PipInstaller(PackageManagerInstaller): def __init__(self): super(PipInstaller, self).__init__(pip_detect, supports_depends=True) def get_install_command(self, resolved, interactive=True, reinstall=False): if not is_pip_installed(): raise InstallFailed((PIP_INSTALLER, "pip is not installed")) # convenience function that calls outs to our detect function packages = self.get_packages_to_install(resolved, reinstall=reinstall) if not packages: return [] else: return [['sudo', 'pip', 'install', '-U', p] for p in packages] The pattern is fairly simple to implement for other package managers. You must provide a ``detect_function(package_names)`` (e.g. ``pip_detect()``) that returns a list of package names that are already installed. You must also implement ``get_install_command()`` which must return a *list* of commands to execute in order to install the relevant packages. Testing ------- If you contribute a support for a new OS/package manager, you *must* provide complete unit test coverage. For example, if your detector relies on parsing the output of a package manager, you must submit example output along with tests that parse them correctly. Test files for os detection should be placed in ``test/os_name``. Setup :: pip install nose pip install mock rosdep2 uses `Python nose `_ for testing, which is a fairly simple and straightfoward test framework. You just have to write a function start with the name ``test`` and use normal ``assert`` statements for your tests. rosdep2 also uses `mock `_ to create mocks for testing. You can run the tests, including coverage, as follows: :: cd rosdep2/test nosetests Documentation ------------- Sphinx is used to provide API documentation for rospkg. The documents are stored in the ``doc`` subdirectory. In order to build the docs, you need the 'ros-theme', which should be stored in `~/sphinx/ros-theme`. You can get a copy of ros-theme from: https://github.com/willowgarage/catkin-sphinx/tree/master/theme ros-rosdep-0.11.4/doc/make.bat000066400000000000000000000106371260171354700160610ustar00rootroot00000000000000@ECHO OFF REM Command file for Sphinx documentation if "%SPHINXBUILD%" == "" ( set SPHINXBUILD=sphinx-build ) set BUILDDIR=_build set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% . if NOT "%PAPER%" == "" ( set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% ) if "%1" == "" goto help if "%1" == "help" ( :help echo.Please use `make ^` where ^ is one of echo. html to make standalone HTML files echo. dirhtml to make HTML files named index.html in directories echo. singlehtml to make a single large HTML file echo. pickle to make pickle files echo. json to make JSON files echo. htmlhelp to make HTML files and a HTML help project echo. qthelp to make HTML files and a qthelp project echo. devhelp to make HTML files and a Devhelp project echo. epub to make an epub echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter echo. text to make text files echo. man to make manual pages echo. changes to make an overview over all changed/added/deprecated items echo. linkcheck to check all external links for integrity echo. doctest to run all doctests embedded in the documentation if enabled goto end ) if "%1" == "clean" ( for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i del /q /s %BUILDDIR%\* goto end ) if "%1" == "html" ( %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html if errorlevel 1 exit /b 1 echo. echo.Build finished. The HTML pages are in %BUILDDIR%/html. goto end ) if "%1" == "dirhtml" ( %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml if errorlevel 1 exit /b 1 echo. echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. goto end ) if "%1" == "singlehtml" ( %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml if errorlevel 1 exit /b 1 echo. echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml. goto end ) if "%1" == "pickle" ( %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle if errorlevel 1 exit /b 1 echo. echo.Build finished; now you can process the pickle files. goto end ) if "%1" == "json" ( %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json if errorlevel 1 exit /b 1 echo. echo.Build finished; now you can process the JSON files. goto end ) if "%1" == "htmlhelp" ( %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp if errorlevel 1 exit /b 1 echo. echo.Build finished; now you can run HTML Help Workshop with the ^ .hhp project file in %BUILDDIR%/htmlhelp. goto end ) if "%1" == "qthelp" ( %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp if errorlevel 1 exit /b 1 echo. echo.Build finished; now you can run "qcollectiongenerator" with the ^ .qhcp project file in %BUILDDIR%/qthelp, like this: echo.^> qcollectiongenerator %BUILDDIR%\qthelp\rosdep.qhcp echo.To view the help file: echo.^> assistant -collectionFile %BUILDDIR%\qthelp\rosdep.ghc goto end ) if "%1" == "devhelp" ( %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp if errorlevel 1 exit /b 1 echo. echo.Build finished. goto end ) if "%1" == "epub" ( %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub if errorlevel 1 exit /b 1 echo. echo.Build finished. The epub file is in %BUILDDIR%/epub. goto end ) if "%1" == "latex" ( %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex if errorlevel 1 exit /b 1 echo. echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. goto end ) if "%1" == "text" ( %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text if errorlevel 1 exit /b 1 echo. echo.Build finished. The text files are in %BUILDDIR%/text. goto end ) if "%1" == "man" ( %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man if errorlevel 1 exit /b 1 echo. echo.Build finished. The manual pages are in %BUILDDIR%/man. goto end ) if "%1" == "changes" ( %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes if errorlevel 1 exit /b 1 echo. echo.The overview file is in %BUILDDIR%/changes. goto end ) if "%1" == "linkcheck" ( %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck if errorlevel 1 exit /b 1 echo. echo.Link check complete; look for any errors in the above output ^ or in %BUILDDIR%/linkcheck/output.txt. goto end ) if "%1" == "doctest" ( %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest if errorlevel 1 exit /b 1 echo. echo.Testing of doctests in the sources finished, look at the ^ results in %BUILDDIR%/doctest/output.txt. goto end ) :end ros-rosdep-0.11.4/doc/man/000077500000000000000000000000001260171354700152205ustar00rootroot00000000000000ros-rosdep-0.11.4/doc/man/rosdep.1000066400000000000000000000064201260171354700166000ustar00rootroot00000000000000.TH "ROSDEP" "1" "January 12, 2012" "0.1" "rosdep" .SH NAME rosdep \- rosdep command . .nr rst2man-indent-level 0 . .de1 rstReportMargin \\$1 \\n[an-margin] level \\n[rst2man-indent-level] level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] - \\n[rst2man-indent0] \\n[rst2man-indent1] \\n[rst2man-indent2] .. .de1 INDENT .\" .rstReportMargin pre: . RS \\$1 . nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] . nr rst2man-indent-level +1 .\" .rstReportMargin post: .. .de UNINDENT . RE .\" indent \\n[an-margin] .\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] .nr rst2man-indent-level -1 .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. .\" Man page generated from reStructeredText. . .SH SYNOPSIS .sp \fBrosdep\fP <\fIcommand\fP> [\fIoptions\fP] [\fIargs\fP] .SH DESCRIPTION .sp The \fBrosdep\fP command helps you install external dependencies in an OS\-independent manner. For example, what Debian packages do you need in order to get the OpenGL headers on Ubuntu? How about OS X? Fedora? rosdep can answer this question for your platform and install the necessary package(s). .sp For more information on rosdep, see \fI\%http://ros.org/wiki/rosdep\fP. .sp Run "rosdep \-h" or "rosdep \-h" to access the built\-in tool documentation. .SH COMMANDS .sp \fBcheck ...\fP .INDENT 0.0 .INDENT 3.5 Check if the dependencies of ROS package(s) have been met. .UNINDENT .UNINDENT .sp \fBinstall ...\fP .INDENT 0.0 .INDENT 3.5 Install dependencies for specified ROS packages. .UNINDENT .UNINDENT .sp \fBdb ...\fP .INDENT 0.0 .INDENT 3.5 Display the dependency database for package(s). .UNINDENT .UNINDENT .sp \fBkeys ...\fP .INDENT 0.0 .INDENT 3.5 List the rosdep keys that the ROS packages depend on. .UNINDENT .UNINDENT .sp \fBwhat\-needs ...\fP .INDENT 0.0 .INDENT 3.5 Print a list of packages that declare a rosdep on (at least one of) .UNINDENT .UNINDENT .sp \fBwhere\-defined ...\fP .INDENT 0.0 .INDENT 3.5 Print a list of YAML files that declare a rosdep on (at least one of) .UNINDENT .UNINDENT .SH OPTIONS .sp \fB\-\-os=OS_NAME:OS_VERSION\fP .INDENT 0.0 .INDENT 3.5 Override OS name and version (colon\-separated), e.g. ubuntu:lucid .UNINDENT .UNINDENT .sp \fB\-i, \-\-include_duplicates\fP .INDENT 0.0 .INDENT 3.5 Do not deduplicate .UNINDENT .UNINDENT .sp \fB\-a, \-\-all\fP .INDENT 0.0 .INDENT 3.5 Select all ROS packages. Only valid for commands that take as arguments. .UNINDENT .UNINDENT .sp \fB\-h, \-\-help\fP .INDENT 0.0 .INDENT 3.5 Show usage information .UNINDENT .UNINDENT .sp \fB\-v, \-\-verbose\fP .INDENT 0.0 .INDENT 3.5 Enable verbose output .UNINDENT .UNINDENT .SH INSTALL OPTIONS .sp \fB\-\-reinstall\fP .INDENT 0.0 .INDENT 3.5 (re)install all dependencies, even if already installed .UNINDENT .UNINDENT .sp \fB\-y, \-\-default\-yes\fP .INDENT 0.0 .INDENT 3.5 Tell the package manager to default to y or fail when installing .UNINDENT .UNINDENT .sp \fB\-s, \-\-simulate\fP .INDENT 0.0 .INDENT 3.5 Simulate install .UNINDENT .UNINDENT .sp \fB\-r\fP .INDENT 0.0 .INDENT 3.5 Continue installing despite errors. .UNINDENT .UNINDENT .SH AUTHOR Tully Foote, Ken Conley .SH COPYRIGHT 2011, Willow Garage .\" Generated by docutils manpage writer. .\" . ros-rosdep-0.11.4/doc/man/rosdep.rst000066400000000000000000000042051260171354700172470ustar00rootroot00000000000000:orphan: rosdep manual page ================== Synopsis -------- **rosdep** <*command*> [*options*] [*args*] Description ----------- The **rosdep** command helps you install external dependencies in an OS-independent manner. For example, what Debian packages do you need in order to get the OpenGL headers on Ubuntu? How about OS X? Fedora? rosdep can answer this question for your platform and install the necessary package(s). For more information on rosdep, see http://ros.org/wiki/rosdep. Run "rosdep -h" or "rosdep -h" to access the built-in tool documentation. Commands -------- **check ...** Check if the dependencies of ROS package(s) have been met. **db** Display the local rosdep database. **init** Initialize /etc/ros/sources.list.d/ configuration. May require sudo. **install ...** Install dependencies for specified ROS packages. **keys ...** List the rosdep keys that the ROS packages depend on. **resolve ...** Resolve to system dependencies **update** Update the local rosdep database based on the rosdep sources. **what-needs ...** Print a list of packages that declare a rosdep on (at least one of) **where-defined ...** Print a list of YAML files that declare a rosdep on (at least one of) Options ------- **--os=OS_NAME:OS_VERSION** Override OS name and version (colon-separated), e.g. ubuntu:lucid **-c SOURCES_CACHE_DIR, --sources-cache-dir=SOURCES_CACHE_DIR** Override default sources cache directory (local rosdep database). **-a, --all** Select all ROS packages. Only valid for commands that take as arguments. **-h, --help** Show usage information **-v, --verbose** Enable verbose output Install Options --------------- **--reinstall** (re)install all dependencies, even if already installed **-y, --default-yes** Tell the package manager to default to y or fail when installing **-s, --simulate** Simulate install **-r** Continue installing despite errors. **-R** Install implicit/recursive dependencies. ros-rosdep-0.11.4/doc/overview.rst000066400000000000000000000040761260171354700170540ustar00rootroot00000000000000Overview ======== Installing rosdep ----------------- rosdep2 is available using pip or easy_install:: sudo pip install -U rosdep or:: sudo easy_install -U rosdep rospkg Setting up rosdep ----------------- rosdep needs to be initialized and updated to use:: sudo rosdep init rosdep update ``sudo rosdep init`` will create a `sources list `_ directory in ``/etc/ros/rosdep/sources.list.d`` that controls where rosdep gets its data from. ``rosdep update`` reads through this sources list to initialize your local database. Updating rosdep --------------- You can update your rosdep database by running:: rosdep update Installating rosdeps -------------------- rosdep takes in the name of a ROS stack or package that you wish to install the system dependencies for. Common installation workflow:: $ rosdep check ros_comm All system dependencies have been satisified $ rosdep install geometry If you're worried about ``rosdep install`` bringing in system dependencies you don't want, you can run ``rosdep install -s `` instead to "simulate" the installation. You will be able to see the commands that rosdep would have run. Example:: $ rosdep install -s ros_comm #[apt] Installation commands: sudo apt-get install libapr1-dev sudo apt-get install libaprutil1-dev sudo apt-get install libbz2-dev sudo apt-get install liblog4cxx10-dev sudo apt-get install pkg-config sudo apt-get install python-imaging sudo apt-get install python-numpy sudo apt-get install python-paramiko sudo apt-get install python-yaml You can also query rosdep to find out more information about specific dependencies:: $ rosdep keys roscpp pkg-config $ rosdep resolve pkg-config pkg-config $ rosdep keys geometry eigen apr glut python-sip python-numpy graphviz paramiko cppunit libxext log4cxx pkg-config $ rosdep resolve eigen libeigen3-dev For more information, please see the :ref:`command reference `. ros-rosdep-0.11.4/doc/ros.png000066400000000000000000000147701260171354700157670ustar00rootroot00000000000000PNG  IHDR)֌QsRGB pHYs  tIME (MIDATx|wtT׵9NQC $Fa:l`M1a;ϸ-_\b18!`'q؀B $Pm4sw2H~]Z3ZS{ȿP_j뛝VfC zM-[ZmfkP!: ۥ`$I&)\+,]^fab; |]/}bk5>4$01Cz\iY_ZPqBDX҅z`b745yO6#( &Iҷe:wj0gMI{r9)~ᜉS&tfW@,E/ǭ6o;xF-+NjFϘ/PUv9⍽TʻP$Q{}Mzʐq.z@) O.HK;f@x޵;v/hd?fieѭJ$Ƣ(Ym933֬㹩C嵇0422Z9/"ܟ{},dݨSqQݽdJa/ ~@Fp0)+ <›w\>c'_? 6R9q 0g_m!hTpҥ!~v_}XVra p 蒙"nޗ2>- li8s;$I%?gq~њu!̽9\~A1DQ 1iLoǹp$l=7ȫM`-ms_aF]C+ 80@j)w˜{ǎ,!,x޳MbbV/|ph;VßNolnRtA!*&"4ثq'd`̨}ȨMyݐDsk{umg8',˔ܮzOfunnv0R!/Q=2{Aʋw:aΙ4's|-A#Y:,@aެ2}өOwU+S$h˫yAdYF^JFG!d(<ŷ6x,`s s "ƒRL?*%9_gk3[־K CQxk|=(I?ڲm1(YZӅ >ΐ`X(򵛕5MznSګc]yahy;ܸa&WPzB:_H@4jmm9s Q^p9KK{?`S򰸩8.9$ԝ8}ir:Oܙ6jA)o=y6o,V-WL7&4x`:ܒ"Iq})cGӔ߹ CPV^{!( !OT̲Vmf\eH,mM=Shxe8>8KHܶ IJC͖c.=29cySZsw2LeUGtaBeEZm ׽4w50;Aa;k͹k+ooUc],J !I {x\9o8_A(TR1C7n BbY/:"IJM[͜^RJµΫc#0򍋬88Η TXi@M6XVƔ/C@8b >a͞%])E3Rk}9kj's:_PaESRqCQR#<}6/<@L&$$ xRAEIH5\ j ea|jR% ܫ,1@[hTi)Ck[̌Ic{c\2R545VΫxV#٪=t|h^ѩ:ZUkjVky^Udi)C?{O<ڍҜ7r99-",ν~l ?8-z@@afMȜjkh9/jXp}$ISؘn&;`_޼^X<30_GGJʪ[ZBz*al .Y vp?u#3Mm{"",$9@{%KYy0!Z/o7f@ؚGX2s_l]تfXKRr(zf\jҴcߧ25iLxhRaVeGsYA'7>5^qټ^hhj'(J.ya zZj߲p'+9x\|a/t-gB8m>ªAYh;m) B dzcKOe ӜokeVޟެ =odlqf\~w_4v46R۽[P2 b I(&*ܕϙ;ϾǚۛZo9|t|\LD.fyocqIECckqi塣~wjfh B0,_8 AёGO]lk@DSs{0fnfB>!OӪu J_u7bٻح6nj)<utɹTx9fsn Y=@d(زsW z-2,t:6=tf,FVX4Vz6" Q,Kk5*_}υ$tXEAb\Y޾hNbf)J;o}ꥏ_, v乼־٦Q!l@a3m3BC::r᪵Ne_Xjmg/+U14DؘQ]27[^QwwǓHX"ꉳy6]S+Hstz: L-7eۮU54Mʹ]yU}'~nztIS($} Gcjnݮ*-jXHzUq]pp'`>OGr?@^UpHQzx~L` `,Jyݡ,$`:-By+% b3Sn/bk/\&۱ vAu -9 岧,Ƹ # "I\fw҇LkC7T,PƸN5.jIv6mҘ%ݭs+!Ӫ}ẀpA=b2t|t/0 'MNP\MSw*w.NWfLN5wDQruɽ5ժ5jFzprB}i ZW/ׅ:,v%5HӔFjJjH=B[lcFO3n\CV,ԨU&o$>}|Qɠs8]l:yl̩iC;,6%Xڋ{\~v+d@1Pvk36u>LSjE )#-~`Wz̩im~gI#ա"wKE` A "du8y^xd-^BG /(*k3[VM!1%ͭSI!=bPѭfC' x8poJrrAW=2;בm$ɋjuZ\FH4q\kVIt&a$$7q\LӫG9)A7kjzaBMm$QB# !D q ZzҸ߽UbZ-W Jlv|[̹yax?_QW/pa!gkhWDY`Q:޾SQKQ(@PU9y*䎚A$,I]Cs%eUm^1*1uQ#G&%Dޣl_Ȱ;QЌ]Gs?[KuIENDB`ros-rosdep-0.11.4/doc/rosdep2_api.rst000066400000000000000000000026721260171354700174150ustar00rootroot00000000000000.. _python_api: rosdep2 Python API ================== .. module:: rosdep2 **Experimental**: the rosdep2 Python library is still unstable. The :mod:`rosdep` Python module supports both the `rosdep` command-line tool as well as libraries that wish to use rosdep data files to resolve dependencies. As a developer, you may wish to extend :mod:`rosdep` to add new OS platforms or package managers. Platforms are specified by registering information on the :class:`InstallerContext`. Package managers generally extend the :class:`PackageManagerInstaller` implementation. The :mod:`rospkg` library is used for OS detection. Please consult the :ref:`Developers Guide ` for more information on developing with the Python API. .. contents:: Table of Contents :depth: 2 Exceptions ---------- .. autoclass:: InvalidData Database Model -------------- .. autoclass:: RosdepDatabase :members: .. autoclass:: RosdepDatabaseEntry :members: View Model ---------- .. autoclass:: RosdepDefinition :members: .. autoclass:: RosdepView :members: .. autoclass:: RosdepLookup :members: Loaders ------- .. autoclass:: RosdepLoader :members: .. autoclass:: RosPkgLoader :members: Installers ---------- .. autoclass:: InstallerContext :members: .. autoclass:: Installer :members: .. autoclass:: PackageManagerInstaller :members: Indices and tables ------------------ * :ref:`genindex` * :ref:`modindex` * :ref:`search` ros-rosdep-0.11.4/doc/rosdep_yaml_format.rst000066400000000000000000000070211260171354700210650ustar00rootroot00000000000000.. _rosdep_yaml: rosdep YAML format '''''''''''''''''' The current rosdep YAML format specification was introduced in `REP 111 `_. Specification ============= rosdep supports both a *simple* and *versioned* syntax. * Simple :: ROSDEP_NAME: OS_NAME1: PACKAGE_MANAGER1: PACKAGE_ARGUMENTS_A OS_NAME2: PACKAGE_MANAGER2: PACKAGE_ARGUMENTS_A * Versioned :: ROSDEP_NAME: OS_NAME1: OS_VERSION1: PACKAGE_MANAGER1: PACKAGE_ARGUMENTS_A OS_VERSION2: PACKAGE_MANAGER2: PACKAGE_ARGUMENTS_A2 The names above resolve as follows: * ``ROSDEP_NAME`` is the name referred to by manifest files. Examples: ``log4cxx`` or ``gtest``. * ``OS_NAME`` is the name of an OS. Examples: ``ubuntu``, ``osx``, ``fedora``, ``debian``, or ``windows``. * ``OS_VERSION`` (*optional*) is the name of specific versions in the OS. Examples: ``lucid`` or ``squeeze``. If no ``OS_VERSION`` is specified, the rule is assumed to apply to all versions. * ``PACKAGE_MANAGER`` (*optional in ROS Electric, required in ROS Fuerte*) is a key to select which package manager to use for this rosdep. Examples: ``apt``, ``easy_install``, ``macports``. * ``PACKAGE_ARGUMENT`` is free-form YAML that is be passed to the handler for the specified ``PACKAGE_MANAGER``. Example ------- For Ubuntu the default package manager is apt. An example for the simple syntax is: :: rosdep_name: ubuntu: apt: packages: [ debian-package-name, other-debian-package-name] or versioned as follows: :: rosdep_name: ubuntu: lucid: apt: packages: [debian-package-name, other-debian-package-name] OS name identifiers and supported package managers -------------------------------------------------- * ``arch``: Arch Linux * ``pacman`` (default) * ``source`` * ``cygwin``: Cygwin * ``apt-cyg`` * ``source`` * ``debian``: Debian GNU/Linux * ``apt`` (default) * ``source`` * ``fedora``: Fedora Project * ``yum`` (default) * ``source`` * ``freebsd``: FreeBSD * ``pkg_add`` (default) * ``source`` * ``osx`` : Apple OS X * TODO: special notes on macports vs. homebrew * ``opensuse``: OpenSUSE * ``zypper`` (default) * ``source`` * ``rhel`` : Red Hat Enterprise Linux * ``yum`` (default) * ``source`` * ``ubuntu``: Ubuntu * ``apt`` (default) * ``pip`` * ``source`` For backwards compatibility, ``macports`` is supported as an alias of ``osx``. OS version identifiers ---------------------- OS version identifiers use one-word codenames that refer to particular releases. Examples: * debian: ``squeeze`` * ubuntu: ``lucid``, ``maverick``, ``natty``, ``oneiric``, ``precise`` * osx: ``snow``, ``lion`` Disambiguation of OS_VERSION and PACKAGE_MANAGER ------------------------------------------------ For backwards compatibility, the ``PACKAGE_MANAGER`` is allowed to be optional in the ROS Electric case. As both ``PACKAGE_MANAGER`` and ``OS_VERSION`` are optional, this creates an ambiguious case where either ``OS_VERSION`` or ``PACKAGE_MANAGER`` is specified, but not both. In this ambiguous case, rosdep first interprets the key as a ``PACKAGE_MANAGER``. If this test fails, it will be interpreted as an ``OS_VERSION``. Developers should exercise caution in keeping ``OS_VERSION`` and ``PACKAGE_MANAGER`` keys globally distinct. ros-rosdep-0.11.4/doc/sources_list.rst000066400000000000000000000054471260171354700177270ustar00rootroot00000000000000rosdep sources list =================== The :command:`rosdep` command-line tool is similar to other tools like :command:`apt` that use a *sources list* to update a local index. rosdep 2 loads *valid data sources* specified in the sources list in order. This follows the behavior of apt, which designates the "most preferred source listed first." Each rosdep entry from the data sources is combined into a single rosdep database. Entries from data sources listed higher in the sources have higher precedence. The first entry for a rosdep key "wins". Subsequent entries for the same key, even if they are non-conflicting, are not merged. A data source is considered *valid* if all of its tags match the local tags. A data source with no tags is always loaded. Updating the local index ------------------------ A new local index can be generated by running ``rosdep update``. Sources list file format ------------------------ *Sources list* files are loaded from ``/etc/ros/rosdep/sources.list.d``. ``sudo rosdep init`` will create a default configuration for you. rosdep processes the files in this directory, sorted by filename in ascending order. Precedence is assigned to the files in the order they are processed, with the first file having the highest precendence. A ``.list`` file lists *data sources*, with the most preferred data source first. The general format is:: source-type url [tags...] ``source-type`` can be: ``yaml`` ``rosdep.yaml`` file ``gbpdistro`` ``gbpdistro`` file. ``type`` Type must be ``yaml`` or ``gbpdistro``. In the future, more types may be supported. ``url`` URL should point to the HTTP location of a rosdep YAML file. URL must contain an scheme (e.g. ``http://``), hostname, and path. ``tags`` Tags are optional. Currently, the OS name (e.g. ``ubuntu``), OS codename (e.g. ``lucid``), and ROS distribution codename (e.g. ``fuerte``) are supported. These tags are all lower-case. Lines that start with a ``#`` are considered to be comments. Example file:: yaml https://github.com/ros/rosdistro/raw/master/rosdep/base.yaml yaml https://github.com/ros/rosdistro/raw/master/rosdep/python.yaml gbpdistro https://github.com/ros/rosdistro/raw/master/releases/fuerte.yaml fuerte Tags ---- The tags constrain the configurations that the source will be loaded on. *All* tags must match the current configuration for the source to be considered valid. In the example above, the source will only be valid for the ROS Fuerte distribution on an Ubuntu Lucid platform. gbpdistro files --------------- ``gbpdistro`` refers to a ``git-buildpackage``-based toolchain currently in use for building catkin-based ROS stacks. End users are not expected to write their own ``gbpdistro`` files and the specification is unstable. ros-rosdep-0.11.4/rosdoc.yaml000066400000000000000000000000531260171354700160530ustar00rootroot00000000000000 - builder: sphinx sphinx_root_dir: doc ros-rosdep-0.11.4/scripts/000077500000000000000000000000001260171354700153675ustar00rootroot00000000000000ros-rosdep-0.11.4/scripts/rosdep000077500000000000000000000001121260171354700166030ustar00rootroot00000000000000#!/usr/bin/env python from rosdep2.main import rosdep_main rosdep_main() ros-rosdep-0.11.4/scripts/rosdep-source000077500000000000000000000050031260171354700201050ustar00rootroot00000000000000#!/usr/bin/env python # Copyright (c) 2011, 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 the 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. """ Script for installing rdmanifest-described resources """ from __future__ import print_function import os import sys from optparse import OptionParser from rosdep2 import InstallFailed from rosdep2.platforms import source NAME='rosdep-source' def install_main(): parser = OptionParser(usage="usage: %prog install ", prog=NAME) options, args = parser.parse_args() if len(args) != 2: parser.error("please specify one and only one rdmanifest url") if args[0] != 'install': parser.error("currently only support the 'install' command") rdmanifest_url= args[1] try: if os.path.isfile(rdmanifest_url): source.install_from_file(rdmanifest_url) else: source.install_from_url(rdmanifest_url) except InstallFailed as e: print("ERROR: installation failed:\n%s"%e, file=sys.stderr) sys.exit(1) if __name__ == '__main__': install_main() ros-rosdep-0.11.4/setup.py000066400000000000000000000020201260171354700154040ustar00rootroot00000000000000import os from setuptools import setup exec(open(os.path.join(os.path.dirname(__file__), 'src', 'rosdep2', '_version.py')).read()) setup( name='rosdep', version=__version__, packages=['rosdep2', 'rosdep2.platforms'], package_dir={'': 'src'}, install_requires=['catkin_pkg', 'rospkg >= 1.0.34', 'rosdistro >= 0.4.0', 'PyYAML >= 3.1'], setup_requires=['nose >= 1.0'], test_suite='nose.collector', test_requires=['mock'], scripts=['scripts/rosdep', 'scripts/rosdep-source'], author="Tully Foote, Ken Conley", author_email="tfoote@osrfoundation.org", url="http://wiki.ros.org/rosdep", download_url="http://download.ros.org/downloads/rosdep/", keywords=['ROS'], classifiers=[ "Programming Language :: Python", "License :: OSI Approved :: BSD License"], description="rosdep package manager abstrction tool for ROS", long_description="Command-line tool for installing system " "dependencies on a variety of platforms.", license="BSD" ) ros-rosdep-0.11.4/setup.sh000066400000000000000000000004501260171354700153730ustar00rootroot00000000000000SCRIPT_PATH="${BASH_SOURCE[0]}"; if([ -h "${SCRIPT_PATH}" ]) then while([ -h "${SCRIPT_PATH}" ]) do SCRIPT_PATH=`readlink "${SCRIPT_PATH}"`; done fi pushd . > /dev/null cd `dirname ${SCRIPT_PATH}` > /dev/null SCRIPT_PATH=`pwd`; popd > /dev/null export PYTHONPATH=$SCRIPT_PATH/src:$PYTHONPATH ros-rosdep-0.11.4/src/000077500000000000000000000000001260171354700144675ustar00rootroot00000000000000ros-rosdep-0.11.4/src/rosdep2/000077500000000000000000000000001260171354700160455ustar00rootroot00000000000000ros-rosdep-0.11.4/src/rosdep2/__init__.py000066400000000000000000000116311260171354700201600ustar00rootroot00000000000000# Copyright (c) 2009, 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 the 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. # Author Tully Foote/tfoote@willowgarage.com, Ken Conley/kwc@willowgarage.com """ rosdep library and command-line tool """ from __future__ import print_function from ._version import __version__ import sys from .installers import InstallerContext, Installer, \ PackageManagerInstaller from .core import RosdepInternalError, InstallFailed, UnsupportedOs, \ InvalidData, DownloadFailure from .model import RosdepDatabase, RosdepDatabaseEntry from .lookup import RosdepDefinition, RosdepView, RosdepLookup, \ ResolutionError from .loader import RosdepLoader # don't let import error take down code as when attempting to compute version number try: from .rospkg_loader import RosPkgLoader except ImportError: print("Cannot import rospkg, rosdep will not function properly", file=sys.stderr) def create_default_installer_context(verbose=False): from .platforms import arch from .platforms import cygwin from .platforms import debian from .platforms import gentoo from .platforms import opensuse from .platforms import osx from .platforms import pip from .platforms import gem from .platforms import redhat from .platforms import source platform_mods = [arch, cygwin, debian, gentoo, opensuse, osx, redhat] installer_mods = [source, pip, gem] + platform_mods context = InstallerContext() context.set_verbose(verbose) # setup installers for m in installer_mods: if verbose: print("registering installers for %s"%(m.__name__)) m.register_installers(context) # setup platforms for m in platform_mods: if verbose: print("registering platforms for %s"%(m.__name__)) m.register_platforms(context) return context from . import gbpdistro_support gbpdistro_support.create_default_installer_context = create_default_installer_context #TODO: this was partially abstracted from main() for another library, # but it turned out to be unnecessary. Not sure it's worth maintaining # separately, especially in the top-level module. def get_default_installer(installer_context=None, verbose=False): """ Based on the active OS and installer context configuration, get the installer to use and the necessary configuration state (installer keys, OS name/version). :returns: installer, installer_keys, default_key, os_name, os_version. """ if installer_context is None: installer_context = create_default_installer_context(verbose=verbose) os_name, os_version = installer_context.get_os_name_and_version() try: installer_keys = installer_context.get_os_installer_keys(os_name) default_key = installer_context.get_default_os_installer_key(os_name) except KeyError: raise UnsupportedOs(os_name, installer_context.get_os_keys()) installer = installer_context.get_installer(default_key) return installer, installer_keys, default_key, os_name, os_version __all__ = ['InstallerContext', 'Installer', 'PackageManagerInstaller', 'RosdepInternalError', 'InstallFailed', 'UnsupportedOs', 'InvalidData', 'DownloadFailure', 'RosdepDatabase', 'RosdepDatabaseEntry', 'RosdepDefinition', 'RosdepView', 'RosdepLookup', 'ResolutionError', 'RosdepLoader', 'RosPkgLoader', 'get_default_installer', 'create_default_installer_context', ] ros-rosdep-0.11.4/src/rosdep2/_version.py000066400000000000000000000000271260171354700202420ustar00rootroot00000000000000__version__ = '0.11.4' ros-rosdep-0.11.4/src/rosdep2/catkin_packages.py000066400000000000000000000032211260171354700215240ustar00rootroot00000000000000from __future__ import print_function import os import sys try: from catkin_pkg.packages import find_packages except ImportError: print("catkin_pkg was not detected, please install it.", file=sys.stderr) sys.exit(1) _catkin_workspace_packages = [] _catkin_packages_cache = {} def find_catkin_packages_in(path, verbose=False): """ :returns: a list of packages in a given directory :raises: OSError if the path doesn't exist """ global _catkin_packages_cache if not os.path.exists(path): raise OSError("given path '{0}' does not exist".format(path)) if verbose: print("Looking for packages in '{0}'... ".format(path), end='', file=sys.stderr) path = os.path.abspath(path) if path in _catkin_packages_cache: if verbose: print("found in cache.", file=sys.stderr) return _catkin_packages_cache[path] packages = find_packages(path) if type(packages) == dict and packages != {}: package_names = [package.name for package in packages.values()] if verbose: print("found " + str(len(packages)) + " packages.") for package in package_names: print(" {0}".format(package)) _catkin_packages_cache[path] = package_names return package_names else: if verbose: print("failed to find packages.", file=sys.stderr) return [] def set_workspace_packages(packages): global _catkin_workspace_packages _catkin_workspace_packages = list(packages or []) def get_workspace_packages(): global _catkin_workspace_packages return _catkin_workspace_packages ros-rosdep-0.11.4/src/rosdep2/catkin_support.py000077500000000000000000000076701260171354700215010ustar00rootroot00000000000000""" Helper routines for catkin. These are distributed inside of rosdep2 to protect catkin against future rosdep2 API updatese. These helper routines are assumed to run in an interactive mode with an end-user and thus return end-user oriented error messages. Errors are returned as arguments to raised :exc:`ValidationFailed` exceptions. Workflow:: installer = get_installer(APT_INSTALLER) view = get_catkin_view(rosdistro_name, 'ubuntu', 'lucid') resolve_for_os(rosdep_key, view, installer, 'ubuntu', 'lucid') """ from __future__ import print_function import os from subprocess import Popen, PIPE, CalledProcessError from . import create_default_installer_context from .lookup import RosdepLookup from .platforms.debian import APT_INSTALLER from .platforms.osx import BREW_INSTALLER from .platforms.pip import PIP_INSTALLER from .platforms.redhat import YUM_INSTALLER from .rep3 import download_targets_data from .rosdistrohelper import get_targets from .rospkg_loader import DEFAULT_VIEW_KEY from .sources_list import get_sources_list_dir, DataSourceMatcher, SourcesListLoader class ValidationFailed(Exception): pass def call(command, pipe=None): """ Copy of call() function from catkin-generate-debian to mimic output """ working_dir = '.' #print('+ cd %s && ' % working_dir + ' '.join(command)) process = Popen(command, stdout=pipe, stderr=pipe, cwd=working_dir) output, unused_err = process.communicate() retcode = process.poll() if retcode: raise CalledProcessError(retcode, command) if pipe: return output def get_ubuntu_targets(rosdistro): """ Get a list of Ubuntu distro codenames for the specified ROS distribution. This method blocks on an HTTP download. :raises: :exc:`ValidationFailed` """ targets_data = get_targets() legacy_targets = download_targets_data() if 'fuerte' in legacy_targets: targets_data['fuerte'] = {'ubuntu': legacy_targets['fuerte']} if 'electric' in legacy_targets: targets_data['electric'] = {'ubuntu': legacy_targets['electric']} return targets_data[rosdistro]['ubuntu'] def get_installer(installer_name): """ Expected installers APT_INSTALLER, YUM_INSTALLER, ...""" installer_context = create_default_installer_context() return installer_context.get_installer(installer_name) def resolve_for_os(rosdep_key, view, installer, os_name, os_version): """ Resolve rosdep key to dependencies. :param os_name: OS name, e.g. 'ubuntu' :raises: :exc:`rosdep2.ResolutionError` """ d = view.lookup(rosdep_key) ctx = create_default_installer_context() os_installers = ctx.get_os_installer_keys(os_name) default_os_installer = ctx.get_default_os_installer_key(os_name) inst_key, rule = d.get_rule_for_platform(os_name, os_version, os_installers, default_os_installer) assert inst_key in os_installers return installer.resolve(rule) def update_rosdep(): call(('rosdep', 'update'), pipe=PIPE) def get_catkin_view(rosdistro_name, os_name, os_version, update=True): """ :raises: :exc:`ValidationFailed` """ sources_list_dir = get_sources_list_dir() if not os.path.exists(sources_list_dir): raise ValidationFailed("""rosdep database is not initialized, please run: \tsudo rosdep init """) if update: update_rosdep() sources_matcher = DataSourceMatcher([rosdistro_name, os_name, os_version]) sources_loader = SourcesListLoader.create_default(matcher=sources_matcher) if not (sources_loader.sources): raise ValidationFailed("""rosdep database does not have any sources. Please make sure you have a valid configuration in: \t%s """%(sources_list_dir)) # for vestigial reasons, using the roskg loader, but we're only # actually using the backend db as resolution is not resource-name based lookup = RosdepLookup.create_from_rospkg(sources_loader=sources_loader) return lookup.get_rosdep_view(DEFAULT_VIEW_KEY) ros-rosdep-0.11.4/src/rosdep2/core.py000066400000000000000000000065421260171354700173560ustar00rootroot00000000000000# Copyright (c) 2009, 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 the 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. from __future__ import print_function import os import sys import traceback def rd_debug(s): if "ROSDEP_DEBUG" in os.environ: print(s) def print_bold(msg): """ print message printed to screen with bold decoration for greater clarity :param msg: message to print, ``str`` """ if sys.platform in ['win32']: print('%s'%msg) #windows console is terrifically boring else: print('\033[1m%s\033[0m'%msg) class InvalidData(Exception): """ Data is not in valid rosdep format. """ def __init__(self, message, origin=None): super(InvalidData, self).__init__(message) self.origin = origin class UnsupportedOs(Exception): pass class RosdepInternalError(Exception): def __init__(self, e, message=None): self.error = e if message is None: self.message = traceback.format_exc() else: self.message = message def __str__(self): return self.message class CachePermissionError(Exception): """Failure when writing the cache.""" pass class DownloadFailure(Exception): """ Failure downloading sources list data for I/O or other format reasons. """ pass class InstallFailed(Exception): def __init__(self, failure=None, failures=None): """ One of failure/failures must be set. :param failure: single (installer_key, message) tuple. :param failures: list of (installer_key, message) tuples """ if failures is not None: self.failures = failures elif not failure: raise ValueError("failure is None") else: self.failures = [failure] def __str__(self): return '\n'.join(['%s: %s'%(key, message) for (key, message) in self.failures]) ros-rosdep-0.11.4/src/rosdep2/dependency_graph.py000066400000000000000000000142061260171354700217210ustar00rootroot00000000000000# 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 the 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. # Author William Woodall/wjwwood@gmail.com from collections import defaultdict class Resolution(dict): """A default dictionary for use in the :class:`DependencyGraph`.""" def __init__(self): super(Resolution, self).__init__() self['installer_key'] = None self['install_keys'] = [] self['dependencies'] = [] self['is_root'] = True class DependencyGraph(defaultdict): """ Provides a mechanism for generating a list of resolutions which preserves the dependency order. The :class:`DependencyGraph` inherits from a *defaultdict*, so it can be used as such to load the dependency graph data into it. Example:: # Dependency graph:: A-B-C dg = DependencyGraph() dg['A']['installer_key'] = 'a_installer' dg['A']['install_keys'] = ['a'] dg['A']['dependencies'] = ['B'] dg['B']['installer_key'] = 'b_installer' dg['B']['install_keys'] = ['b'] dg['B']['dependencies'] = ['C'] dg['C']['installer_key'] = 'c_installer' dg['C']['install_keys'] = ['c'] dg['C']['dependencies'] = [] result = dg.get_ordered_uninstalled() """ def __init__(self): defaultdict.__init__(self, Resolution) def detect_cycles(self, rosdep_key, traveled_keys): """ Recursive function to detect cycles in the dependency graph. :param rosdep_key: This is the rosdep key to use as the root in the cycle exploration. :param traveled_keys: A list of rosdep_keys that have been traversed thus far. :raises: :exc:`AssertionError` if the rosdep_key is in the traveled keys, indicating a cycle has occurred. """ assert rosdep_key not in traveled_keys, "A cycle in the dependency graph occurred with key `%s`."%rosdep_key traveled_keys.append(rosdep_key) for dependency in self[rosdep_key]['dependencies']: self.detect_cycles(dependency, traveled_keys) def validate(self): """ Performs validations on the dependency graph, like cycle detection and invalid rosdep key detection. :raises: :exc:`AssertionError` if a cycle is detected. :raises: :exc:`KeyError` if an invalid rosdep_key is found in the dependency graph. """ for rosdep_key in self: # Ensure all dependencies have definitions # i.e.: Ensure we aren't pointing to invalid rosdep keys for dependency in self[rosdep_key]['dependencies']: if dependency not in self: raise KeyError("Invalid Graph Structure: rosdep key `%s` does not exist in the dictionary of resolutions."%dependency) self[dependency]['is_root'] = False # Check each entry for cyclical dependencies for rosdep_key in self: self.detect_cycles(rosdep_key, []) def get_ordered_dependency_list(self): """ Generates an ordered list of dependencies using the dependency graph. :returns: *[(installer_key, [install_keys])]*, ``[(str, [str])]``. *installer_key* is the key that denotes which installed the accompanying *install_keys* are for. *installer_key* are something like ``apt`` or ``homebrew``. *install_keys* are something like ``boost`` or ``ros-fuerte-ros_comm``. :raises: :exc:`AssertionError` if a cycle is detected. :raises: :exc:`KeyError` if an invalid rosdep_key is found in the dependency graph. """ # Validate the graph self.validate() # Generate the dependency list dep_list = [] for rosdep_key in self: if self[rosdep_key]['is_root']: dep_list.extend(self.__get_ordered_uninstalled(rosdep_key)) # Make the list unique and remove empty entries result = [] for item in dep_list: if item not in result and item[1] != []: result.append(item) # Squash the results by installer_key squashed_result = [] previous_installer_key = None for installer_key, resolved in result: if previous_installer_key != installer_key: squashed_result.append((installer_key, [])) previous_installer_key = installer_key squashed_result[-1][1].extend(resolved) return squashed_result def __get_ordered_uninstalled(self, key): uninstalled = [] for dependency in self[key]['dependencies']: uninstalled.extend(self.__get_ordered_uninstalled(dependency)) uninstalled.append((self[key]['installer_key'], self[key]['install_keys'])) return uninstalled ros-rosdep-0.11.4/src/rosdep2/gbpdistro_support.py000066400000000000000000000174151260171354700222200ustar00rootroot00000000000000try: from urllib.request import urlopen except ImportError: from urllib2 import urlopen import yaml try: import urlparse except ImportError: import urllib.parse as urlparse #py3k import os from rospkg.os_detect import OS_DEBIAN from rospkg.os_detect import OS_FEDORA from rospkg.os_detect import OS_OSX from rospkg.os_detect import OS_UBUNTU create_default_installer_context = None from .core import InvalidData, DownloadFailure from .platforms.debian import APT_INSTALLER from .platforms.osx import BREW_INSTALLER from .platforms.redhat import YUM_INSTALLER from .rosdistrohelper import get_targets, get_release_file, PreRep137Warning from .rep3 import download_targets_data # deprecated, will output warning import warnings #py3k try: unicode except: basestring = unicode = str # location of an example gbpdistro file for reference and testing FUERTE_GBPDISTRO_URL = 'https://raw.github.com/ros/rosdistro/' \ + 'master/releases/fuerte.yaml' #seconds to wait before aborting download of gbpdistro data DOWNLOAD_TIMEOUT = 15.0 def get_owner_name(url): """ Given a gbpdistro url, returns the name of the github user in the url. If the url is not a valid github url it returns the default `ros`. This information is used to set the homebrew tap name, see: https://github.com/ros-infrastructure/rosdep/pull/17 :returns: The github account in the given gbpdistro url """ result = 'ros' try: parsed = urlparse.urlparse(url) if parsed.netloc == 'github.com': result = parsed.path.split('/')[1] except (ValueError, IndexError): pass return result # For compatability url defaults to '' def gbprepo_to_rosdep_data(gbpdistro_data, targets_data, url=''): """ DEPRECATED: the rosdistro file format has changed according to REP137 this function will yield a deprecation warning :raises: :exc:`InvalidData` """ warnings.warn("deprecated: see REP137 and rosdistro", PreRep137Warning) # Error reporting for this isn't nearly as good as it could be # (e.g. doesn't separate gbpdistro vs. targets, nor provide # origin), but rushing this implementation a bit. try: if not type(targets_data) == dict: raise InvalidData("targets data must be a dict") if not type(gbpdistro_data) == dict: raise InvalidData("gbpdistro data must be a dictionary") if gbpdistro_data['type'] != 'gbp': raise InvalidData('gbpdistro must be of type "gbp"') # compute the default target data for the release_name release_name = gbpdistro_data['release-name'] if not release_name in targets_data: raise InvalidData("targets file does not contain information " + "for release [%s]" % (release_name)) else: # take the first match target_data = targets_data[release_name] # compute the rosdep data for each repo rosdep_data = {} gbp_repos = gbpdistro_data['repositories'] # Ensure gbp_repos is a dict if type(gbp_repos) != dict: raise InvalidData("invalid repo spec in gbpdistro data: " + str(gbp_repos) + ". Invalid repositories entry, must be dict.") for rosdep_key, repo in gbp_repos.items(): if type(repo) != dict: raise InvalidData("invalid repo spec in gbpdistro data: " + str(repo)) for pkg in repo.get('packages', {rosdep_key: None}): rosdep_data[pkg] = {} # for pkg in repo['packages']: indent the rest of the lines here. # Do generation for ubuntu rosdep_data[pkg][OS_UBUNTU] = {} # Do generation for empty OS X entries homebrew_name = '%s/%s/%s' % (get_owner_name(url), release_name, rosdep_key) rosdep_data[pkg][OS_OSX] = { BREW_INSTALLER: {'packages': [homebrew_name]} } # - debian package name: underscores must be dashes deb_package_name = 'ros-%s-%s' % (release_name, pkg) deb_package_name = deb_package_name.replace('_', '-') repo_targets = repo['target'] if 'target' in repo else 'all' if repo_targets == 'all': repo_targets = target_data for t in repo_targets: if not isinstance(t, basestring): raise InvalidData("invalid target spec: %s" % (t)) # rosdep_data[pkg][OS_UBUNTU][t] = { rosdep_data[pkg][OS_UBUNTU][t] = { APT_INSTALLER: {'packages': [deb_package_name]} } rosdep_data[pkg]['_is_ros'] = True return rosdep_data except KeyError as e: raise InvalidData("Invalid GBP-distro/targets format: missing key: " + str(e)) # REP137 compliant def get_gbprepo_as_rosdep_data(gbpdistro): """ :raises: :exc:`InvalidData` """ distro_file = get_release_file(gbpdistro) ctx = create_default_installer_context() release_name = gbpdistro rosdep_data = {} default_installers = {} gbp_repos = distro_file.repositories for rosdep_key, repo in gbp_repos.items(): for pkg in repo.package_names: rosdep_data[pkg] = {} # following rosdep pull #17, use env var instead of github organization name tap = os.environ.get('ROSDEP_HOMEBREW_TAP', 'ros') # Do generation for empty OS X entries homebrew_name = '%s/%s/%s' % (tap, release_name, rosdep_key) rosdep_data[pkg][OS_OSX] = { BREW_INSTALLER: {'packages': [homebrew_name]} } # - package name: underscores must be dashes package_name = 'ros-%s-%s' % (release_name, pkg) package_name = package_name.replace('_', '-') for os_name in distro_file.platforms: if not os_name in rosdep_data[pkg]: rosdep_data[pkg][os_name] = {} if not os_name in default_installers: default_installers[os_name] = ctx.get_default_os_installer_key(os_name) for os_code_name in distro_file.platforms[os_name]: rosdep_data[pkg][os_name][os_code_name] = { default_installers[os_name]: {'packages': [package_name]} } rosdep_data[pkg]['_is_ros'] = True return rosdep_data def download_gbpdistro_as_rosdep_data(gbpdistro_url, targets_url=None): """ Download gbpdistro file from web and convert format to rosdep distro data. DEPRECATED: see REP137. This function will output (at least) one deprecation warning :param gbpdistro_url: url of gbpdistro file, ``str`` :param target_url: override URL of platform targets file :raises: :exc:`DownloadFailure` :raises: :exc:`InvalidData` If targets file does not pass cursory validation checks. """ # we can convert a gbpdistro file into rosdep data by following a # couple rules # will output a warning targets_data = download_targets_data(targets_url=targets_url) try: f = urlopen(gbpdistro_url, timeout=DOWNLOAD_TIMEOUT) text = f.read() f.close() gbpdistro_data = yaml.safe_load(text) # will output a warning return gbprepo_to_rosdep_data(gbpdistro_data, targets_data, gbpdistro_url) except Exception as e: raise DownloadFailure("Failed to download target platform data " + "for gbpdistro:\n\t" + str(e)) ros-rosdep-0.11.4/src/rosdep2/installers.py000066400000000000000000000554031260171354700206060ustar00rootroot00000000000000# Copyright (c) 2009, 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 the 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. # Author Tully Foote/tfoote@willowgarage.com, Ken Conley/kwc@willowgarage.com from __future__ import print_function import subprocess import traceback from rospkg.os_detect import OsDetect from .core import rd_debug, RosdepInternalError, InstallFailed, print_bold, InvalidData # kwc: InstallerContext is basically just a bunch of dictionaries with # defined lookup methods. It really encompasses two facets of a # rosdep configuration: the pluggable nature of installers and # platforms, as well as the resolution of the operating system for a # specific machine. It is possible to decouple those two notions, # though there are some touch points over how this interfaces with the # rospkg.os_detect library, i.e. how platforms can tweak these # detectors and how the higher-level APIs can override them. class InstallerContext(object): """ :class:`InstallerContext` manages the context of execution for rosdep as it relates to the installers, OS detectors, and other extensible APIs. """ def __init__(self, os_detect=None): """ :param os_detect: (optional) :class:`rospkg.os_detect.OsDetect` instance to use for detecting platforms. If `None`, default instance will be used. """ # platform configuration self.installers = {} self.os_installers = {} self.default_os_installer = {} # stores configuration of which value to use for the OS version key (version number or codename) self.os_version_type = {} # OS detection and override if os_detect is None: os_detect = OsDetect() self.os_detect = os_detect self.os_override = None self.verbose = False def set_verbose(self, verbose): self.verbose = verbose def set_os_override(self, os_name, os_version): """ Override the OS detector with *os_name* and *os_version*. See :meth:`InstallerContext.detect_os`. :param os_name: OS name value to use, ``str`` :param os_version: OS version value to use, ``str`` """ if self.verbose: print("overriding OS to [%s:%s]"%(os_name, os_version)) self.os_override = os_name, os_version def get_os_version_type(self, os_name): return self.os_version_type.get(os_name, OsDetect.get_version) def set_os_version_type(self, os_name, version_type): if not hasattr(version_type, '__call__'): raise ValueError("version type should be a method") self.os_version_type[os_name] = version_type def get_os_name_and_version(self): """ Get the OS name and version key to use for resolution and installation. This will be the detected OS name/version unless :meth:`InstallerContext.set_os_override()` has been called. :returns: (os_name, os_version), ``(str, str)`` """ if self.os_override: return self.os_override else: os_name = self.os_detect.get_name() os_key = self.get_os_version_type(os_name) os_version = os_key(self.os_detect) return os_name, os_version def get_os_detect(self): """ :returns os_detect: :class:`OsDetect` instance used for detecting platforms. """ return self.os_detect def set_installer(self, installer_key, installer): """ Set the installer to use for *installer_key*. This will replace any existing installer associated with the key. *installer_key* should be the same key used for the ``rosdep.yaml`` package manager key. If *installer* is ``None``, this will delete any existing associated installer from this context. :param installer_key: key/name to associate with installer, ``str`` :param installer: :class:`Installer` implementation, ``class``. :raises: :exc:`TypeError` if *installer* is not a subclass of :class:`Installer` """ if installer is None: del self.installers[installer_key] return if not isinstance(installer, Installer): raise TypeError("installer must be a instance of Installer") if self.verbose: print("registering installer [%s]"%(installer_key)) self.installers[installer_key] = installer def get_installer(self, installer_key): """ :returns: :class:`Installer` class associated with *installer_key*. :raises: :exc:`KeyError` If not associated installer :raises: :exc:`InstallFailed` If installer cannot produce an install command (e.g. if installer is not installed) """ return self.installers[installer_key] def get_installer_keys(self): """ :returns: list of registered installer keys """ return self.installers.keys() def get_os_keys(self): """ :returns: list of OS keys that have registered with this context, ``[str]`` """ return self.os_installers.keys() def add_os_installer_key(self, os_key, installer_key): """ Register an installer for the specified OS. This will fail with a :exc:`KeyError` if no :class:`Installer` can be found with the associated *installer_key*. :param os_key: Key for OS :param installer_key: Key for installer to add to OS :raises: :exc:`KeyError`: if installer for *installer_key* is not set. """ # validate, will throw KeyError self.get_installer(installer_key) if self.verbose: print("add installer [%s] to OS [%s]"%(installer_key, os_key)) if os_key in self.os_installers: self.os_installers[os_key].append(installer_key) else: self.os_installers[os_key] = [installer_key] def get_os_installer_keys(self, os_key): """ Get list of installer keys registered for the specified OS. These keys can be resolved by calling :meth:`InstallerContext.get_installer`. :param os_key: Key for OS :raises: :exc:`KeyError`: if no information for OS *os_key* is registered. """ if os_key in self.os_installers: return self.os_installers[os_key][:] else: raise KeyError(os_key) def set_default_os_installer_key(self, os_key, installer_key): """ Set the default OS installer to use for OS. :meth:`InstallerContext.add_os_installer` must have previously been called with the same arguments. :param os_key: Key for OS :param installer_key: Key for installer to add to OS :raises: :exc:`KeyError`: if installer for *installer_key* is not set or if OS for *os_key* has no associated installers. """ if not os_key in self.os_installers: raise KeyError("unknown OS: %s"%(os_key)) if not hasattr(installer_key, '__call__'): raise ValueError("version type should be a method") if not installer_key(self.os_detect) in self.os_installers[os_key]: raise KeyError("installer [%s] is not associated with OS [%s]. call add_os_installer_key() first"%(installer_key(self.os_detect), os_key)) if self.verbose: print("set default installer for OS [%s]"%(os_key,)) self.default_os_installer[os_key] = installer_key def get_default_os_installer_key(self, os_key): """ Get the default OS installer key to use for OS, or ``None`` if there is no default. :param os_key: Key for OS :returns: :class:`Installer` :raises: :exc:`KeyError`: if no information for OS *os_key* is registered. """ if not os_key in self.os_installers: raise KeyError("unknown OS: %s"%(os_key)) try: installer_key = self.default_os_installer[os_key](self.os_detect) if not installer_key in self.os_installers[os_key]: raise KeyError("installer [%s] is not associated with OS [%s]. call add_os_installer_key() first"%(installer_key, os_key)) # validate, will throw KeyError self.get_installer(installer_key) return installer_key except KeyError: return None class Installer(object): """ The :class:`Installer` API is designed around opaque *resolved* parameters. These parameters can be any type of sequence object, but they must obey set arithmetic. They should also implement ``__str__()`` methods so they can be pretty printed. """ def is_installed(self, resolved_item): """ :param resolved: resolved installation item. NOTE: this is a single item, not a list of items like the other APIs, ``opaque``. :returns: ``True`` if all of the *resolved* items are installed on the local system """ raise NotImplementedError("is_installed", resolved_item) def get_install_command(self, resolved, interactive=True, reinstall=False, quiet=False): """ :param resolved: list of resolved installation items, ``[opaque]`` :param interactive: If `False`, disable interactive prompts, e.g. Pass through ``-y`` or equivalant to package manager. :param reinstall: If `True`, install everything even if already installed """ raise NotImplementedError("get_package_install_command", resolved, interactive, reinstall, quiet) def get_depends(self, rosdep_args): """ :returns: list of dependencies on other rosdep keys. Only necessary if the package manager doesn't handle dependencies. """ return [] # Default return empty list def resolve(self, rosdep_args_dict): """ :param rosdep_args_dict: argument dictionary to the rosdep rule for this package manager :returns: [resolutions]. resolved objects should be printable to a user, but are otherwise opaque. """ raise NotImplementedError("Base class resolve", rosdep_args_dict) def unique(self, *resolved_rules): """ Combine the resolved rules into a unique list. This is meant to combine the results of multiple calls to :meth:`PackageManagerInstaller.resolve`. Example:: resolved1 = installer.resolve(args1) resolved2 = installer.resolve(args2) resolved = installer.unique(resolved1, resolved2) :param *resolved_rules: resolved arguments. Resolved arguments must all be from this :class:`Installer` instance. """ raise NotImplementedError("Base class unique", resolved_rules) class PackageManagerInstaller(Installer): """ General form of a package manager :class:`Installer` implementation that assumes: - installer rosdep args spec is a list of package names stored with the key "packages" - a detect function exists that can return a list of packages that are installed Also, if *supports_depends* is set to ``True``: - installer rosdep args spec can also include dependency specification with the key "depends" """ def __init__(self, detect_fn, supports_depends=False): """ :param supports_depends: package manager supports dependency key """ self.detect_fn = detect_fn self.supports_depends = supports_depends self.as_root = True self.sudo_command = 'sudo -H' def elevate_priv(self, cmd): """ Prepend *self.sudo_command* to the command if *self.as_root* is ``True``. :param list cmd: list of strings comprising the command :returns: a list of commands """ return (self.sudo_command.split() if self.as_root else []) + cmd def resolve(self, rosdep_args): """ See :meth:`Installer.resolve()` """ packages = None if type(rosdep_args) == dict: packages = rosdep_args.get("packages", []) if type(packages) == type("string"): packages = packages.split() elif type(rosdep_args) == type('str'): packages = rosdep_args.split(' ') elif type(rosdep_args) == list: packages = rosdep_args else: raise InvalidData("Invalid rosdep args: %s"%(rosdep_args)) return packages def unique(self, *resolved_rules): """ See :meth:`Installer.unique()` """ s = set() for resolved in resolved_rules: s.update(resolved) return sorted(list(s)) def get_packages_to_install(self, resolved, reinstall=False): if reinstall: return resolved if not resolved: return [] else: return list(set(resolved) - set(self.detect_fn(resolved))) def is_installed(self, resolved_item): return not self.get_packages_to_install([resolved_item]) def get_install_command(self, resolved, interactive=True, reinstall=False, quiet=False): raise NotImplementedError('subclasses must implement', resolved, interactive, reinstall, quiet) def get_depends(self, rosdep_args): """ :returns: list of dependencies on other rosdep keys. Only necessary if the package manager doesn't handle dependencies. """ if self.supports_depends and type(rosdep_args) == dict: return rosdep_args.get('depends', []) return [] # Default return empty list class RosdepInstaller(object): def __init__(self, installer_context, lookup): self.installer_context = installer_context self.lookup = lookup def get_uninstalled(self, resources, implicit=False, verbose=False): """ Get list of system dependencies that have not been installed as well as a list of errors from performing the resolution. This is a bulk API in order to provide performance optimizations in checking install state. :param resources: List of resource names (e.g. ROS package names), ``[str]]`` :param implicit: Install implicit (recursive) dependencies of resources. Default ``False``. :returns: (uninstalled, errors), ``({str: [opaque]}, {str: ResolutionError})``. Uninstalled is a dictionary with the installer_key as the key. :raises: :exc:`RosdepInternalError` """ installer_context = self.installer_context # resolutions have been unique()d if verbose: print("resolving for resources [%s]"%(', '.join(resources))) resolutions, errors = self.lookup.resolve_all(resources, installer_context, implicit=implicit) # for each installer, figure out what is left to install uninstalled = [] if resolutions == []: return uninstalled, errors for installer_key, resolved in resolutions: #py3k if verbose: print("resolution: %s [%s]" % (installer_key, ', '.join([str(r) for r in resolved]))) try: installer = installer_context.get_installer(installer_key) except KeyError as e: # lookup has to be buggy to cause this raise RosdepInternalError(e) try: packages_to_install = installer.get_packages_to_install(resolved) except Exception as e: rd_debug(traceback.format_exc()) raise RosdepInternalError(e, message="Bad installer [%s]: %s"%(installer_key, e)) # only create key if there is something to do if packages_to_install: uninstalled.append((installer_key, packages_to_install)) if verbose: print("uninstalled: [%s]"%(', '.join([str(p) for p in packages_to_install]))) return uninstalled, errors def install(self, uninstalled, interactive=True, simulate=False, continue_on_error=False, reinstall=False, verbose=False, quiet=False): """ Install the uninstalled rosdeps. This API is for the bulk workflow of rosdep (see example below). For a more targeted install API, see :meth:`RosdepInstaller.install_resolved`. :param uninstalled: uninstalled value from :meth:`RosdepInstaller.get_uninstalled`. Value is a dictionary mapping installer key to a dictionary with resolution data, ``{str: {str: vals}}`` :param interactive: If ``False``, suppress interactive prompts (e.g. by passing '-y' to ``apt``). :param simulate: If ``False`` simulate installation without actually executing. :param continue_on_error: If ``True``, continue installation even if an install fails. Otherwise, stop after first installation failure. :param reinstall: If ``True``, install dependencies if even already installed (default ``False``). :raises: :exc:`InstallFailed` if any rosdeps fail to install and *continue_on_error* is ``False``. :raises: :exc:`KeyError` If *uninstalled* value has invalid installer keys Example:: uninstalled, errors = installer.get_uninstalled(packages) installer.install(uninstalled) """ if verbose: print("install options: reinstall[%s] simulate[%s] interactive[%s]"%(reinstall, simulate, interactive)) print("install: uninstalled keys are %s"%(', '.join([', '.join(pkg) for pkg in [v for k,v in uninstalled]]))) # Squash uninstalled again, in case some dependencies were already installed squashed_uninstalled = [] previous_installer_key = None for installer_key, resolved in uninstalled: if previous_installer_key != installer_key: squashed_uninstalled.append((installer_key, [])) previous_installer_key = installer_key squashed_uninstalled[-1][1].extend(resolved) failures = [] for installer_key, resolved in squashed_uninstalled: try: self.install_resolved(installer_key, resolved, simulate=simulate, interactive=interactive, reinstall=reinstall, continue_on_error=continue_on_error, verbose=verbose, quiet=quiet) except InstallFailed as e: if not continue_on_error: raise else: #accumulate errors failures.extend(e.failures) if failures: raise InstallFailed(failures=failures) def install_resolved(self, installer_key, resolved, simulate=False, interactive=True, reinstall=False, continue_on_error=False, verbose=False, quiet=False): """ Lower-level API for installing a rosdep dependency. The rosdep keys have already been resolved to *installer_key* and *resolved* via :exc:`RosdepLookup` or other means. :param installer_key: Key for installer to apply to *resolved*, ``str`` :param resolved: Opaque resolution list from :class:`RosdepLookup`. :param interactive: If ``True``, allow interactive prompts (default ``True``) :param simulate: If ``True``, don't execute installation commands, just print to screen. :param reinstall: If ``True``, install dependencies if even already installed (default ``False``). :param verbose: If ``True``, print verbose output to screen (default ``False``) :param quiet: If ``True``, supress output except for errors (default ``False``) :raises: :exc:`InstallFailed` if any of *resolved* fail to install. """ installer_context = self.installer_context installer = installer_context.get_installer(installer_key) command = installer.get_install_command(resolved, interactive=interactive, reinstall=reinstall, quiet=quiet) if not command: if verbose: print("#No packages to install") return if simulate: print("#[%s] Installation commands:"%(installer_key)) for sub_command in command: print(' '+' '.join(sub_command)) # nothing left to do for simulation if simulate: return # run each install command set and collect errors failures = [] for sub_command in command: # always echo commands to screen print_bold("executing command [%s]"%' '.join(sub_command)) result = subprocess.call(sub_command) if verbose: print("command return code [%s]: %s"%(' '.join(sub_command), result)) if result != 0: failures.append((installer_key, 'command [%s] failed'%(' '.join(sub_command))) ) if not continue_on_error: raise InstallFailed(failures=failures) # test installation of each for r in resolved: if not installer.is_installed(r): failures.append((installer_key, "Failed to detect successful installation of [%s]"%(r))) # finalize result if failures: raise InstallFailed(failures=failures) elif verbose: print("#successfully installed") ros-rosdep-0.11.4/src/rosdep2/loader.py000066400000000000000000000076531260171354700177000ustar00rootroot00000000000000# Copyright (c) 2011, 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 the 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. # Author Ken Conley/kwc@willowgarage.com """ Base API for loading rosdep information by package or stack name. This API is decoupled from the ROS packaging system to enable multiple implementations of rosdep, including ones that don't rely on the ROS packaging system. This is necessary, for example, to implement a version of rosdep that works against tarballs of released stacks. """ import yaml from .core import InvalidData ROSDEP_YAML = 'rosdep.yaml' class RosdepLoader: """ Base API for loading rosdep information by package or stack name. """ def load_rosdep_yaml(self, yaml_contents, origin): """ Utility routine for unmarshalling rosdep data encoded as YAML. :param origin: origin of yaml contents (for error messages) :raises: :exc:`yaml.YAMLError` """ try: return yaml.load(yaml_contents) except yaml.YAMLError as e: raise InvalidData("Invalid YAML in [%s]: %s"%(origin, e), origin=origin) def load_view(self, view_name, rosdep_db, verbose=False): """ Load view data into rosdep_db. If the view has already been loaded into rosdep_db, this method does nothing. :param view_name: name of ROS stack to load, ``str`` :param rosdep_db: database to load stack data into, :class:`RosdepDatabase` :raises: :exc:`InvalidData` :raises: :exc:`rospkg.ResourceNotFound` if view cannot be located """ raise NotImplementedError(view_name, rosdep_db, verbose) #pychecker def get_loadable_resources(self): raise NotImplementedError() def get_loadable_views(self): raise NotImplementedError() def get_rosdeps(self, resource_name, implicit=True): """ :raises: :exc:`rospkg.ResourceNotFound` if *resource_name* cannot be found. """ raise NotImplementedError(resource_name, implicit) #pychecker def get_view_key(self, resource_name): """ Map *resource_name* to a view key. In rospkg, this maps a ROS package name to a ROS stack name. If *resource_name* is a ROS stack name, it returns the ROS stack name. :returns: Name of view that *resource_name* is in, ``None`` if no associated view. :raises: :exc:`rospkg.ResourceNotFound` if *resource_name* cannot be found. """ raise NotImplementedError(resource_name) ros-rosdep-0.11.4/src/rosdep2/lookup.py000066400000000000000000000662031260171354700177370ustar00rootroot00000000000000# Copyright (c) 2011, 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 the 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. # Author Tully Foote/tfoote@willowgarage.com, Ken Conley/kwc@willowgarage.com from __future__ import print_function import sys import yaml from collections import defaultdict from rospkg import RosPack, RosStack, ResourceNotFound from .core import RosdepInternalError, InvalidData, rd_debug from .model import RosdepDatabase from .rospkg_loader import RosPkgLoader from .dependency_graph import DependencyGraph from .sources_list import SourcesListLoader from . import catkin_packages class RosdepDefinition(object): """ Single rosdep dependency definition. This data is stored as the raw dictionary definition for the dependency. See REP 111, 'Multiple Package Manager Support for Rosdep' for a discussion of this raw format. """ def __init__(self, rosdep_key, data, origin=""): """ :param rosdep_key: key/name of rosdep dependency :param data: raw rosdep data for a single rosdep dependency, ``dict`` :param origin: string that indicates where data originates from (e.g. filename) """ self.rosdep_key = rosdep_key if not isinstance(data, dict): raise InvalidData("rosdep data for [%s] must be a dictionary" % (self.rosdep_key), origin=origin) self.data = data self.origin = origin def reverse_merge(self, new_data, origin="", verbose=False): """ Merge two definitions together, with existing rules taking precendence. Definitions are merged at the os_name level, meaning that if two rules exist with the same os_name, the first one wins. :param data: raw rosdep data for a single rosdep dependency, ``dict`` :param origin: string that indicates where this new data comes from (e.g. filename) """ for os_name, rules in new_data.items(): if os_name not in self.data: if verbose: print("[%s] adding rules for os [%s] to [%s]"%(origin, os_name, self.rosdep_key), file=sys.stderr) self.data[os_name] = rules elif verbose: print("[%s] ignoring [%s] for os [%s], already loaded"%(origin, self.rosdep_key, os_name), file=sys.stderr) def get_rule_for_platform(self, os_name, os_version, installer_keys, default_installer_key): """ Get installer_key and rule for the specified rule. See REP 111 for precedence rules. :param os_name: OS name to get rule for :param os_version: OS version to get rule for :param installer_keys: Keys of installers for platform, ``[str]`` :param default_installer_key: Default installer key for platform, ``[str]`` :returns: (installer_key, rosdep_args_dict), ``(str, dict)`` :raises: :exc:`ResolutionError` If no rule is available :raises: :exc:`InvalidData` If rule data is not valid """ rosdep_key = self.rosdep_key data = self.data if type(data) != dict: raise InvalidData("rosdep value for [%s] must be a dictionary"%(self.rosdep_key), origin=self.origin) if os_name not in data: raise ResolutionError(rosdep_key, data, os_name, os_version, "No definition of [%s] for OS [%s]"%(rosdep_key, os_name)) data = data[os_name] return_key = default_installer_key # REP 111: rosdep first interprets the key as a # PACKAGE_MANAGER. If this test fails, it will be interpreted # as an OS_VERSION_CODENAME. if type(data) == dict: for installer_key in installer_keys: if installer_key in data: data = data[installer_key] return_key = installer_key break else: # data must be a dictionary, string, or list if type(data) == dict: # check for # hardy: # apt: # stuff # we've already checked for PACKAGE_MANAGER_KEY, so # version key must be present here for data to be valid # dictionary value. if os_version not in data: raise ResolutionError(rosdep_key, self.data, os_name, os_version, "No definition of [%s] for OS version [%s]"%(rosdep_key, os_version)) data = data[os_version] if type(data) == dict: for installer_key in installer_keys: if installer_key in data: data = data[installer_key] return_key = installer_key break if type(data) not in (dict, list, type('str')): raise InvalidData("rosdep OS definition for [%s:%s] must be a dictionary, string, or list: %s"%(self.rosdep_key, os_name, data), origin=self.origin) return return_key, data def __str__(self): return "%s:\n%s"%(self.origin, yaml.dump(self.data, default_flow_style=False)) class ResolutionError(Exception): def __init__(self, rosdep_key, rosdep_data, os_name, os_version, message): self.rosdep_key = rosdep_key self.rosdep_data = rosdep_data self.os_name = os_name self.os_version = os_version super(ResolutionError, self).__init__(message) def __str__(self): if self.rosdep_data: pretty_data = yaml.dump(self.rosdep_data, default_flow_style=False) else: pretty_data = '' return """%s \trosdep key : %s \tOS name : %s \tOS version : %s \tData: %s"""%(self.args[0], self.rosdep_key, self.os_name, self.os_version, pretty_data) class RosdepView(object): """ View of :class:`RosdepDatabase`. Unlike :class:`RosdepDatabase`, which stores :class:`RosdepDatabaseEntry` data for all stacks, a view merges entries for a particular stack. This view can then be queries to lookup and resolve individual rosdep dependencies. """ def __init__(self, name): self.name = name self.rosdep_defs = {} # {str: RosdepDefinition} def __str__(self): return '\n'.join(["%s: %s"%val for val in self.rosdep_defs.items()]) def lookup(self, rosdep_name): """ :returns: :class:`RosdepDefinition` :raises: :exc:`KeyError` If *rosdep_name* is not declared """ return self.rosdep_defs[rosdep_name] def keys(self): """ :returns: list of rosdep names in this view """ return self.rosdep_defs.keys() def merge(self, update_entry, override=False, verbose=False): """ Merge rosdep database update into main database. Merge rules are first entry to declare a key wins. There are no conflicts. This rule logic is modelled after the apt sources list. :param override: Ignore first-one-wins rules and instead always use rules from update_entry """ if verbose: print("view[%s]: merging from cache of [%s]"%(self.name, update_entry.origin)) db = self.rosdep_defs for dep_name, dep_data in update_entry.rosdep_data.items(): # convert data into RosdepDefinition model update_definition = RosdepDefinition(dep_name, dep_data, update_entry.origin) # First rule wins or override, no rule-merging. if override or not dep_name in db: db[dep_name] = update_definition elif dep_name in db: db[dep_name].reverse_merge(dep_data, update_entry.origin, verbose=verbose) def prune_catkin_packages(rosdep_keys, verbose=False): workspace_pkgs = catkin_packages.get_workspace_packages() if not workspace_pkgs: return rosdep_keys for i, rosdep_key in reversed(list(enumerate(rosdep_keys))): if rosdep_key in workspace_pkgs: # If workspace packages listed (--catkin-workspace) # and if the rosdep_key is a package in that # workspace, then skip it rather than resolve it if verbose: print("rosdep key '{0}'".format(rosdep_key) + " is in the catkin workspace, skipping.", file=sys.stderr) del rosdep_keys[i] return rosdep_keys def prune_skipped_packages(rosdep_keys, skipped_keys, verbose=False): if not skipped_keys: return rosdep_keys for i, rosdep_key in reversed(list(enumerate(rosdep_keys))): if rosdep_key in skipped_keys: # If the key is in the list of keys to explicitly skip, skip it if verbose: print("rosdep key '{0}'".format(rosdep_key) + " was listed in the skipped packages, skipping.", file=sys.stderr) del rosdep_keys[i] return rosdep_keys class RosdepLookup(object): """ Lookup rosdep definitions. Provides API for most non-install-related commands for rosdep. :class:`RosdepLookup` caches data as it is loaded, so changes made on the filesystem will not be reflected if the rosdep information has already been loaded. """ def __init__(self, rosdep_db, loader): """ :param loader: Loader to use for loading rosdep data by stack name, ``RosdepLoader`` :param rosdep_db: Database to load definitions into, :class:`RosdepDatabase` """ self.rosdep_db = rosdep_db self.loader = loader self._view_cache = {} # {str: {RosdepView}} self._resolve_cache = {} # {str : (os_name, os_version, installer_key, resolution, dependencies)} # some APIs that deal with the entire environment save errors # in to self.errors instead of raising them in order to be # robust to single-stack faults. self.errors = [] # flag for turning on printing to console self.verbose = False self.skipped_keys = [] def get_loader(self): return self.loader def get_errors(self): """ Retrieve error state for API calls that do not directly report error state. This is the case for APIs like :meth:`RosdepLookup.where_defined` that are meant to be fault-tolerant to single-stack failures. :returns: List of exceptions, ``[Exception]`` """ return self.errors[:] def get_rosdeps(self, resource_name, implicit=True): """ Get rosdeps that *resource_name* (e.g. package) requires. :param implicit: If ``True``, include implicit rosdep dependencies. Default: ``True``. :returns: list of rosdep names, ``[str]`` """ return self.loader.get_rosdeps(resource_name, implicit=implicit) def get_resources_that_need(self, rosdep_name): """ :param rosdep_name: name of rosdep dependency :returns: list of package names that require rosdep, ``[str]`` """ return [k for k in self.loader.get_loadable_resources() if rosdep_name in self.get_rosdeps(k, implicit=False)] @staticmethod def create_from_rospkg(rospack=None, rosstack=None, sources_loader=None, verbose=False): """ Create :class:`RosdepLookup` based on current ROS package environment. :param rospack: (optional) Override :class:`rospkg.RosPack` instance used to crawl ROS packages. :param rosstack: (optional) Override :class:`rospkg.RosStack` instance used to crawl ROS stacks. :param sources_loader: (optional) Override SourcesLoader used for managing sources.list data sources. """ # initialize the loader if rospack is None: rospack = RosPack() if rosstack is None: rosstack = RosStack() if sources_loader is None: sources_loader = SourcesListLoader.create_default(verbose=verbose) rosdep_db = RosdepDatabase() # Use sources list to initialize rosdep_db. Underlay has no # notion of specific resources, and its view keys are just the # individual sources it can load from. SourcesListLoader # cannot do delayed evaluation of OS setting due to matcher. underlay_key = SourcesListLoader.ALL_VIEW_KEY # Create the rospkg loader on top of the underlay loader = RosPkgLoader(rospack=rospack, rosstack=rosstack, underlay_key=underlay_key) # create our actual instance lookup = RosdepLookup(rosdep_db, loader) # load in the underlay lookup._load_all_views(loader=sources_loader) # use dependencies to implement precedence view_dependencies = sources_loader.get_loadable_views() rosdep_db.set_view_data(underlay_key, {}, view_dependencies, underlay_key) return lookup def resolve_all(self, resources, installer_context, implicit=False): """ Resolve all the rosdep dependencies for *resources* using *installer_context*. :param resources: list of resources (e.g. packages), ``[str]`` :param installer_context: :class:`InstallerContext` :param implicit: Install implicit (recursive) dependencies of resources. Default ``False``. :returns: (resolutions, errors), ``([(str, [str])], {str: ResolutionError})``. resolutions provides an ordered list of resolution tuples. A resolution tuple's first element is the installer key (e.g.: apt or homebrew) and the second element is a list of opaque resolution values for that installer. errors maps package names to an :exc:`ResolutionError` or :exc:`KeyError` exception. :raises: :exc:`RosdepInternalError` if unexpected error in constructing dependency graph :raises: :exc:`InvalidData` if a cycle occurs in constructing dependency graph """ depend_graph = DependencyGraph() errors = {} # TODO: resolutions dictionary should be replaced with resolution model instead of mapping (undefined) keys. for resource_name in resources: try: rosdep_keys = self.get_rosdeps(resource_name, implicit=implicit) if self.verbose: print("resolve_all: resource [%s] requires rosdep keys [%s]"%(resource_name, ', '.join(rosdep_keys)), file=sys.stderr) rosdep_keys = prune_catkin_packages(rosdep_keys, self.verbose) rosdep_keys = prune_skipped_packages(rosdep_keys, self.skipped_keys, self.verbose) for rosdep_key in rosdep_keys: try: installer_key, resolution, dependencies = \ self.resolve(rosdep_key, resource_name, installer_context) depend_graph[rosdep_key]['installer_key'] = installer_key depend_graph[rosdep_key]['install_keys'] = list(resolution) depend_graph[rosdep_key]['dependencies'] = list(dependencies) while dependencies: depend_rosdep_key = dependencies.pop() # prevent infinite loop if depend_rosdep_key in depend_graph: continue installer_key, resolution, more_dependencies = \ self.resolve(depend_rosdep_key, resource_name, installer_context) dependencies.extend(more_dependencies) depend_graph[depend_rosdep_key]['installer_key'] = installer_key depend_graph[depend_rosdep_key]['install_keys'] = list(resolution) depend_graph[depend_rosdep_key]['dependencies'] = list(more_dependencies) except ResolutionError as e: errors[resource_name] = e except ResourceNotFound as e: errors[resource_name] = e try: # TODO: I really don't like AssertionErrors here; this should be modeled as 'CyclicGraphError' # or something more explicit. No need to continue if this API errors. resolutions_flat = depend_graph.get_ordered_dependency_list() except AssertionError as e: raise InvalidData("cycle in dependency graph detected: %s"%(e)) except KeyError as e: raise RosdepInternalError(e) return resolutions_flat, errors def resolve(self, rosdep_key, resource_name, installer_context): """ Resolve a :class:`RosdepDefinition` for a particular os/version spec. :param resource_name: resource (e.g. ROS package) to resolve key within :param rosdep_key: rosdep key to resolve :param os_name: OS name to use for resolution :param os_version: OS name to use for resolution :returns: *(installer_key, resolution, dependencies)*, ``(str, [opaque], [str])``. *resolution* are the system dependencies for the specified installer. The value is an opaque list and meant to be interpreted by the installer. *dependencies* is a list of rosdep keys that the definition depends on. :raises: :exc:`ResolutionError` If *rosdep_key* cannot be resolved for *resource_name* in *installer_context* :raises: :exc:`rospkg.ResourceNotFound` if *resource_name* cannot be located """ os_name, os_version = installer_context.get_os_name_and_version() view = self.get_rosdep_view_for_resource(resource_name) if view is None: raise ResolutionError(rosdep_key, None, os_name, os_version, "[%s] does not have a rosdep view"%(resource_name)) try: #print("KEYS", view.rosdep_defs.keys()) definition = view.lookup(rosdep_key) except KeyError: rd_debug(view) raise ResolutionError(rosdep_key, None, os_name, os_version, "Cannot locate rosdep definition for [%s]"%(rosdep_key)) # check cache: the main motivation for the cache is that # source rosdeps are expensive to resolve if rosdep_key in self._resolve_cache: cache_value = self._resolve_cache[rosdep_key] cache_os_name = cache_value[0] cache_os_version = cache_value[1] cache_view_name = cache_value[2] if cache_os_name == os_name and \ cache_os_version == os_version and \ cache_view_name == view.name: return cache_value[3:] # get the rosdep data for the platform try: installer_keys = installer_context.get_os_installer_keys(os_name) default_key = installer_context.get_default_os_installer_key(os_name) except KeyError: raise ResolutionError(rosdep_key, definition.data, os_name, os_version, "Unsupported OS [%s]"%(os_name)) installer_key, rosdep_args_dict = definition.get_rule_for_platform(os_name, os_version, installer_keys, default_key) # resolve the rosdep data for the platform try: installer = installer_context.get_installer(installer_key) except KeyError: raise ResolutionError(rosdep_key, definition.data, os_name, os_version, "Unsupported installer [%s]"%(installer_key)) resolution = installer.resolve(rosdep_args_dict) dependencies = installer.get_depends(rosdep_args_dict) # cache value self._resolve_cache[rosdep_key] = os_name, os_version, view.name, installer_key, resolution, dependencies return installer_key, resolution, dependencies def _load_all_views(self, loader): """ Load all available view keys. In general, this is equivalent to loading all stacks on the package path. If :exc:`InvalidData` errors occur while loading a view, they will be saved in the *errors* field. :param loader: override self.loader :raises: :exc:`RosdepInternalError` """ for resource_name in loader.get_loadable_views(): try: self._load_view_dependencies(resource_name, loader) except ResourceNotFound as e: self.errors.append(e) except InvalidData as e: self.errors.append(e) def _load_view_dependencies(self, view_key, loader): """ Initialize internal :exc:`RosdepDatabase` on demand. Not thread-safe. :param view_key: name of view to load dependencies for. :raises: :exc:`rospkg.ResourceNotFound` If view cannot be located :raises: :exc:`InvalidData` if view's data is invaid :raises: :exc:`RosdepInternalError` """ rd_debug("_load_view_dependencies[%s]"%(view_key)) db = self.rosdep_db if db.is_loaded(view_key): return try: loader.load_view(view_key, db, verbose=self.verbose) entry = db.get_view_data(view_key) rd_debug("_load_view_dependencies[%s]: %s"%(view_key, entry.view_dependencies)) for d in entry.view_dependencies: self._load_view_dependencies(d, loader) except InvalidData: # mark view as loaded: as we are caching, the valid # behavior is to not attempt loading this view ever # again. db.mark_loaded(view_key) # re-raise raise except KeyError as e: raise RosdepInternalError(e) def create_rosdep_view(self, view_name, view_keys, verbose=False): """ :param view_name: name of view to create :param view_keys: order list of view names to merge, first one wins :param verbose: print debugging output """ # Create view and initialize with dbs from all of the # dependencies. view = RosdepView(view_name) db = self.rosdep_db for view_key in view_keys: db_entry = db.get_view_data(view_key) view.merge(db_entry, verbose=verbose) if verbose: print("View [%s], merged views:\n"%(view_name)+"\n".join([" * %s"%view_key for view_key in view_keys]), file=sys.stderr) return view def get_rosdep_view_for_resource(self, resource_name, verbose=False): """ Get a :class:`RosdepView` for a specific ROS resource *resource_name*. Views can be queries to resolve rosdep keys to definitions. :param resource_name: Name of ROS resource (e.g. stack, package) to create view for, ``str``. :returns: :class:`RosdepView` for specific ROS resource *resource_name*, or ``None`` if no view is associated with this resource. :raises: :exc:`RosdepConflict` if view cannot be created due to conflict rosdep definitions. :raises: :exc:`rospkg.ResourceNotFound` if *view_key* cannot be located :raises: :exc:`RosdepInternalError` """ view_key = self.loader.get_view_key(resource_name) if not view_key: #NOTE: this may not be the right behavior and this happens #for packages that are not in a stack. return None return self.get_rosdep_view(view_key, verbose=verbose) def get_rosdep_view(self, view_key, verbose=False): """ Get a :class:`RosdepView` associated with *view_key*. Views can be queries to resolve rosdep keys to definitions. :param view_key: Name of rosdep view (e.g. ROS stack name), ``str`` :raises: :exc:`RosdepConflict` if view cannot be created due to conflict rosdep definitions. :raises: :exc:`rospkg.ResourceNotFound` if *view_key* cannot be located :raises: :exc:`RosdepInternalError` """ if view_key in self._view_cache: return self._view_cache[view_key] # lazy-init self._load_view_dependencies(view_key, self.loader) # use dependencies to create view try: dependencies = self.rosdep_db.get_view_dependencies(view_key) except KeyError as e: # convert to ResourceNotFound. This should be decoupled # in the future raise ResourceNotFound(str(e.args[0])) # load views in order view = self.create_rosdep_view(view_key, dependencies + [view_key], verbose=verbose) self._view_cache[view_key] = view return view def get_views_that_define(self, rosdep_name): """ Locate all views that directly define *rosdep_name*. A side-effect of this method is that all available rosdep files in the configuration will be loaded into memory. Error state from single-stack failures (e.g. :exc:`InvalidData`, :exc:`ResourceNotFound`) are not propagated. Caller must check :meth:`RosdepLookup.get_errors` to check for single-stack error state. Error state does not reset -- it accumulates. :param rosdep_name: name of rosdep to lookup :returns: list of (stack_name, origin) where rosdep is defined. :raises: :exc:`RosdepInternalError` """ #TODOXXX: change this to return errors object so that caller cannot ignore self._load_all_views(self.loader) db = self.rosdep_db retval = [] for view_name in db.get_view_names(): entry = db.get_view_data(view_name) # not much abstraction in the entry object if rosdep_name in entry.rosdep_data: retval.append((view_name, entry.origin)) return retval ros-rosdep-0.11.4/src/rosdep2/main.py000066400000000000000000001035651260171354700173550ustar00rootroot00000000000000#!/usr/bin/env python # Copyright (c) 2009, 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 the 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. # Author Tully Foote/tfoote@willowgarage.com """ Command-line interface to rosdep library """ from __future__ import print_function import os import sys import traceback try: from urllib.error import URLError from urllib.request import build_opener from urllib.request import HTTPBasicAuthHandler from urllib.request import HTTPHandler from urllib.request import install_opener from urllib.request import ProxyHandler except ImportError: from urllib2 import build_opener from urllib2 import HTTPBasicAuthHandler from urllib2 import HTTPHandler from urllib2 import install_opener from urllib2 import ProxyHandler from urllib2 import URLError import warnings from optparse import OptionParser import rospkg from . import create_default_installer_context, get_default_installer from . import __version__ from .core import RosdepInternalError, InstallFailed, UnsupportedOs, InvalidData, CachePermissionError from .installers import RosdepInstaller from .lookup import RosdepLookup, ResolutionError from .rospkg_loader import DEFAULT_VIEW_KEY from .sources_list import update_sources_list, get_sources_cache_dir,\ download_default_sources_list, SourcesListLoader,CACHE_INDEX,\ get_sources_list_dir, get_default_sources_list_file,\ DEFAULT_SOURCES_LIST_URL from .rosdistrohelper import PreRep137Warning from .catkin_packages import find_catkin_packages_in from .catkin_packages import set_workspace_packages from .catkin_packages import get_workspace_packages class UsageError(Exception): pass _usage = """usage: rosdep [options] Commands: rosdep check ... check if the dependencies of package(s) have been met. rosdep install ... generate a bash script and then execute it. rosdep db generate the dependency database and print it to the console. rosdep init initialize rosdep sources in /etc/ros/rosdep. May require sudo. rosdep keys ... list the rosdep keys that the packages depend on. rosdep resolve resolve to system dependencies rosdep update update the local rosdep database based on the rosdep sources. rosdep what-needs ... print a list of packages that declare a rosdep on (at least one of) rosdep where-defined ... print a list of yaml files that declare a rosdep on (at least one of) rosdep fix-permissions Recursively change the permissions of the user's ros home directory. May require sudo. Can be useful to fix permissions after calling "rosdep update" with sudo accidentally. """ def _get_default_RosdepLookup(options): """ Helper routine for converting command-line options into appropriate RosdepLookup instance. """ os_override = convert_os_override_option(options.os_override) sources_loader = SourcesListLoader.create_default(sources_cache_dir=options.sources_cache_dir, os_override=os_override, verbose=options.verbose) lookup = RosdepLookup.create_from_rospkg(sources_loader=sources_loader) lookup.verbose = options.verbose return lookup def rosdep_main(args=None): if args is None: args = sys.argv[1:] try: exit_code = _rosdep_main(args) if exit_code not in [0, None]: sys.exit(exit_code) except rospkg.ResourceNotFound as e: print(""" ERROR: Rosdep cannot find all required resources to answer your query %s """%(error_to_human_readable(e)), file=sys.stderr) sys.exit(1) except UsageError as e: print(_usage, file=sys.stderr) print("ERROR: %s"%(str(e)), file=sys.stderr) sys.exit(os.EX_USAGE) except RosdepInternalError as e: print(""" ERROR: Rosdep experienced an internal error. Please go to the rosdep page [1] and file a bug report with the message below. [1] : http://www.ros.org/wiki/rosdep rosdep version: %s %s """%(__version__, e.message), file=sys.stderr) sys.exit(1) except ResolutionError as e: print(""" ERROR: %s %s """%(e.args[0], e), file=sys.stderr) sys.exit(1) except CachePermissionError as e: print(str(e)) print("Try running 'sudo rosdep fix-permissions'") sys.exit(1) except UnsupportedOs as e: print("Unsupported OS: %s\nSupported OSes are [%s]"%(e.args[0], ', '.join(e.args[1])), file=sys.stderr) sys.exit(1) except Exception as e: print(""" ERROR: Rosdep experienced an error: %s Please go to the rosdep page [1] and file a bug report with the stack trace below. [1] : http://www.ros.org/wiki/rosdep rosdep version: %s %s """%(e, __version__, traceback.format_exc()), file=sys.stderr) sys.exit(1) def check_for_sources_list_init(sources_cache_dir): """ Check to see if sources list and cache are present. *sources_cache_dir* alone is enough to pass as the user has the option of passing in a cache dir. If check fails, tell user how to resolve and sys exit. """ commands = [] filename = os.path.join(sources_cache_dir, CACHE_INDEX) if os.path.exists(filename): return else: commands.append('rosdep update') sources_list_dir = get_sources_list_dir() if not os.path.exists(sources_list_dir): commands.insert(0, 'sudo rosdep init') else: filelist = [f for f in os.listdir(sources_list_dir) if f.endswith('.list')] if not filelist: commands.insert(0, 'sudo rosdep init') if commands: commands = '\n'.join([" %s"%c for c in commands]) print(""" ERROR: your rosdep installation has not been initialized yet. Please run: %s """%(commands), file=sys.stderr) sys.exit(1) else: return True def key_list_to_dict(key_list): """ Convert a list of strings of the form 'foo:bar' to a dictionary. Splits strings of the form 'foo:bar quux:quax' into separate entries. """ try: key_list = [key for s in key_list for key in s.split(' ')] return dict(map(lambda s: [t.strip() for t in s.split(':')], key_list)) except ValueError as e: raise UsageError("Invalid 'key:value' list: '%s'" % ' '.join(key_list)) def str_to_bool(s): """Maps a string to bool. Supports true/false, and yes/no, and is case-insensitive""" s = s.lower() if s in ['yes', 'true']: return True elif s in ['no', 'false']: return False else: raise UsageError("Cannot parse '%s' as boolean" % s) def setup_proxy_opener(): # check for http[s]?_proxy user for scheme in ['http', 'https']: key = scheme + '_proxy' if key in os.environ: proxy = ProxyHandler({scheme: os.environ[key]}) auth = HTTPBasicAuthHandler() opener = build_opener(proxy, auth, HTTPHandler) install_opener(opener) def _rosdep_main(args): # sources cache dir is our local database. default_sources_cache = get_sources_cache_dir() parser = OptionParser(usage=_usage, prog='rosdep') parser.add_option("--os", dest="os_override", default=None, metavar="OS_NAME:OS_VERSION", help="Override OS name and version (colon-separated), e.g. ubuntu:lucid") parser.add_option("-c", "--sources-cache-dir", dest="sources_cache_dir", default=default_sources_cache, metavar='SOURCES_CACHE_DIR', help="Override %s"%(default_sources_cache)) parser.add_option("--verbose", "-v", dest="verbose", default=False, action="store_true", help="verbose display") parser.add_option("--version", dest="print_version", default=False, action="store_true", help="print version and exit") parser.add_option("--reinstall", dest="reinstall", default=False, action="store_true", help="(re)install all dependencies, even if already installed") parser.add_option("--default-yes", "-y", dest="default_yes", default=False, action="store_true", help="Tell the package manager to default to y or fail when installing") parser.add_option("--simulate", "-s", dest="simulate", default=False, action="store_true", help="Simulate install") parser.add_option("-r", dest="robust", default=False, action="store_true", help="Continue installing despite errors.") parser.add_option("-q", dest="quiet", default=False, action="store_true", help="Suprress output except for errors") parser.add_option("-a", "--all", dest="rosdep_all", default=False, action="store_true", help="select all packages") parser.add_option("-n", dest="recursive", default=True, action="store_false", help="Do not consider implicit/recursive dependencies. Only valid with 'keys', 'check', and 'install' commands.") parser.add_option("--ignore-packages-from-source", "--ignore-src", "-i", dest='ignore_src', default=False, action="store_true", help="Affects the 'check' and 'install' verbs. If " "specified then rosdep will not install keys " "that are found to be catkin packages anywhere in " "the ROS_PACKAGE_PATH or in any of the directories " "given by the --from-paths option.") parser.add_option("--skip-keys", dest='skip_keys', action="append", default=[], help="Affects the 'check' and 'install' verbs. The " "specified rosdep keys will be ignored, i.e. not " "resolved and not installed. The option can be supplied multiple " "times. A space separated list of rosdep keys can also " "be passed as a string. A more permanent solution to " "locally ignore a rosdep key is creating a local rosdep rule " "with an empty list of packages (include it in " "/etc/ros/rosdep/sources.list.d/ before the defaults).") parser.add_option("--filter-for-installers", action="append", default=[], help="Affects the 'db' verb. If supplied, the output of the 'db' " "command is filtered to only list packages whose installer " "is in the provided list. The option can be supplied " "multiple times. A space separated list of installers can also " "be passed as a string. Example: `--filter-for-installers \"apt pip\"`") parser.add_option("--from-paths", dest='from_paths', default=False, action="store_true", help="Affects the 'check', 'keys', and 'install' verbs. " "If specified the arugments to those verbs will be " "considered paths to be searched, acting on all " "catkin packages found there in.") parser.add_option("--rosdistro", dest='ros_distro', default=None, help="Explicitly sets the ROS distro to use, overriding " "the normal method of detecting the ROS distro " "using the ROS_DISTRO environment variable.") parser.add_option("--as-root", default=[], action='append', metavar="INSTALLER_KEY:", help="Override " "whether sudo is used for a specific installer, " "e.g. '--as-root pip:false' or '--as-root \"pip:no homebrew:yes\"'. " "Can be specified multiple times.") options, args = parser.parse_args(args) if options.print_version: print(__version__) sys.exit(0) # flatten list of skipped keys and filter-for-installers options.skip_keys = [key for s in options.skip_keys for key in s.split(' ')] options.filter_for_installers = [inst for s in options.filter_for_installers for inst in s.split(' ')] if len(args) == 0: parser.error("Please enter a command") command = args[0] if not command in _commands: parser.error("Unsupported command %s."%command) args = args[1:] if options.ros_distro: os.environ['ROS_DISTRO'] = options.ros_distro # Convert list of keys to dictionary options.as_root = dict((k, str_to_bool(v)) for k, v in key_list_to_dict(options.as_root).items()) if not command in ['init', 'update', 'fix-permissions']: check_for_sources_list_init(options.sources_cache_dir) elif not command in ['fix-permissions']: setup_proxy_opener() if command in _command_rosdep_args: return _rosdep_args_handler(command, parser, options, args) elif command in _command_no_args: return _no_args_handler(command, parser, options, args) else: return _package_args_handler(command, parser, options, args) def _no_args_handler(command, parser, options, args): if args: parser.error("command [%s] takes no arguments"%(command)) else: return command_handlers[command](options) def _rosdep_args_handler(command, parser, options, args): # rosdep keys as args if options.rosdep_all: parser.error("-a, --all is not a valid option for this command") elif len(args) < 1: parser.error("Please enter arguments for '%s'"%command) else: return command_handlers[command](args, options) def _package_args_handler(command, parser, options, args): if options.rosdep_all: if args: parser.error("cannot specify additional arguments with -a") else: # let the loader filter the -a. This will take out some # packages that are catkinized (for now). lookup = _get_default_RosdepLookup(options) loader = lookup.get_loader() args = loader.get_loadable_resources() not_found = [] elif not args: parser.error("no packages or stacks specified") # package or stack names as args. have to convert stack names to packages. # - overrides to enable testing packages = [] not_found = [] if options.from_paths: for path in args: if options.verbose: print("Using argument '{0}' as a path to search.".format(path)) if not os.path.exists(path): print("given path '{0}' does not exist".format(path)) return 1 path = os.path.abspath(path) if 'ROS_PACKAGE_PATH' not in os.environ: os.environ['ROS_PACKAGE_PATH'] = '{0}'.format(path) else: os.environ['ROS_PACKAGE_PATH'] = '{0}{1}{2}'.format( path, os.pathsep, os.environ['ROS_PACKAGE_PATH'] ) pkgs = find_catkin_packages_in(path, options.verbose) packages.extend(pkgs) # Make packages list unique packages = list(set(packages)) else: rospack = rospkg.RosPack() rosstack = rospkg.RosStack() val = rospkg.expand_to_packages(args, rospack, rosstack) packages = val[0] not_found = val[1] if not_found: raise rospkg.ResourceNotFound(not_found[0], rospack.get_ros_paths()) # Handle the --ignore-src option if command in ['install', 'check'] and options.ignore_src: if options.verbose: print("Searching ROS_PACKAGE_PATH for " "sources: " + str(os.environ['ROS_PACKAGE_PATH'].split(':'))) ws_pkgs = get_workspace_packages() for path in os.environ['ROS_PACKAGE_PATH'].split(':'): path = os.path.abspath(path.strip()) if os.path.exists(path): pkgs = find_catkin_packages_in(path, options.verbose) ws_pkgs.extend(pkgs) elif options.verbose: print("Skipping non-existent path " + path) set_workspace_packages(ws_pkgs) lookup = _get_default_RosdepLookup(options) # Handle the --skip-keys option by pretending that they are packages in the catkin workspace if command in ['install', 'check'] and options.skip_keys: if options.verbose: print("Skipping the specified rosdep keys:\n- " + '\n- '.join(options.skip_keys)) lookup.skipped_keys = options.skip_keys if 0 and not packages: # disable, let individual handlers specify behavior # possible with empty stacks print("No packages in arguments, aborting") return return command_handlers[command](lookup, packages, options) def convert_os_override_option(options_os_override): """ Convert os_override option flag to ``(os_name, os_version)`` tuple, or ``None`` if not set :returns: ``(os_name, os_version)`` tuple if option is set, ``None`` otherwise :raises: :exc:`UsageError` if option is not set properly """ if not options_os_override: return None val = options_os_override if not ':' in val: raise UsageError("OS override must be colon-separated OS_NAME:OS_VERSION, e.g. ubuntu:maverick") os_name = val[:val.find(':')] os_version = val[val.find(':')+1:] return os_name, os_version def configure_installer_context(installer_context, options): """ Configure the *installer_context* from *options*. - Override the OS detector in *installer_context* if necessary. - Set *as_root* for installers if specified. :raises: :exc:`UsageError` If user input options incorrectly """ os_override = convert_os_override_option(options.os_override) if os_override is not None: installer_context.set_os_override(*os_override) for k,v in options.as_root.items(): try: installer_context.get_installer(k).as_root = v except KeyError: raise UsageError("Installer '%s' not defined." % k) def command_init(options): try: data = download_default_sources_list() except URLError as e: print("ERROR: cannot download default sources list from:\n%s\nWebsite may be down."%(DEFAULT_SOURCES_LIST_URL)) return 4 # reuse path variable for error message path = get_sources_list_dir() old_umask = os.umask(0o022) try: if not os.path.exists(path): os.makedirs(path) path = get_default_sources_list_file() if os.path.exists(path): print("ERROR: default sources list file already exists:\n\t%s\nPlease delete if you wish to re-initialize"%(path)) return 1 with open(path, 'w') as f: f.write(data) print("Wrote %s"%(path)) print("Recommended: please run\n\n\trosdep update\n") except IOError as e: print("ERROR: cannot create %s:\n\t%s"%(path, e), file=sys.stderr) return 2 except OSError as e: print("ERROR: cannot create %s:\n\t%s\nPerhaps you need to run 'sudo rosdep init' instead"%(path, e), file=sys.stderr) return 3 finally: os.umask(old_umask) def command_update(options): error_occured = [] def update_success_handler(data_source): print("Hit %s"%(data_source.url)) def update_error_handler(data_source, exc): error_string = "ERROR: unable to process source [%s]:\n\t%s"%(data_source.url, exc) print(error_string, file=sys.stderr) error_occured.append(error_string) sources_list_dir = get_sources_list_dir() # disable deprecation warnings when using the command-line tool warnings.filterwarnings("ignore", category=PreRep137Warning) if not os.path.exists(sources_list_dir): print("ERROR: no sources directory exists on the system meaning rosdep has not yet been initialized.\n\nPlease initialize your rosdep with\n\n\tsudo rosdep init\n") return 1 filelist = [f for f in os.listdir(sources_list_dir) if f.endswith('.list')] if not filelist: print("ERROR: no data sources in %s\n\nPlease initialize your rosdep with\n\n\tsudo rosdep init\n"%sources_list_dir, file=sys.stderr) return 1 try: print("reading in sources list data from %s"%(sources_list_dir)) sources_cache_dir = get_sources_cache_dir() try: if os.geteuid() == 0: print("Warning: running 'rosdep update' as root is not recommended.", file=sys.stderr) print(" You should run 'sudo rosdep fix-permissions' and invoke 'rosdep update' again without sudo.", file=sys.stderr) except AttributeError: # nothing we wanna do under Windows pass update_sources_list(success_handler=update_success_handler, error_handler=update_error_handler) print("updated cache in %s"%(sources_cache_dir)) except InvalidData as e: print("ERROR: invalid sources list file:\n\t%s"%(e), file=sys.stderr) return 1 except IOError as e: print("ERROR: error loading sources list:\n\t%s"%(e), file=sys.stderr) return 1 if error_occured: print ("ERROR: Not all sources were able to be updated.\n[[[") for e in error_occured: print (e) print("]]]") return 1 def command_keys(lookup, packages, options): lookup = _get_default_RosdepLookup(options) rosdep_keys = get_keys(lookup, packages, options.recursive) _print_lookup_errors(lookup) print('\n'.join(rosdep_keys)) def get_keys(lookup, packages, recursive): rosdep_keys = [] for package_name in packages: deps = lookup.get_rosdeps(package_name, implicit=recursive) rosdep_keys.extend(deps) return set(rosdep_keys) def command_check(lookup, packages, options): verbose = options.verbose installer_context = create_default_installer_context(verbose=verbose) configure_installer_context(installer_context, options) installer = RosdepInstaller(installer_context, lookup) uninstalled, errors = installer.get_uninstalled(packages, implicit=options.recursive, verbose=verbose) # pretty print the result if [v for k, v in uninstalled if v]: print("System dependencies have not been satisified:") for installer_key, resolved in uninstalled: if resolved: for r in resolved: print("%s\t%s"%(installer_key, r)) else: print("All system dependencies have been satisified") if errors: for package_name, ex in errors.items(): if isinstance(ex, rospkg.ResourceNotFound): print("ERROR[%s]: resource not found [%s]"%(package_name, ex.args[0]), file=sys.stderr) else: print("ERROR[%s]: %s"%(package_name, ex), file=sys.stderr) if uninstalled: return 1 else: return 0 def error_to_human_readable(error): if isinstance(error, rospkg.ResourceNotFound): return "Missing resource %s"%(error,) elif isinstance(error, ResolutionError): return "%s"%(error.args[0],) else: return "%s"%(error,) def command_install(lookup, packages, options): # map options install_options = dict(interactive=not options.default_yes, verbose=options.verbose, reinstall=options.reinstall, continue_on_error=options.robust, simulate=options.simulate, quiet=options.quiet) # setup installer installer_context = create_default_installer_context(verbose=options.verbose) configure_installer_context(installer_context, options) installer = RosdepInstaller(installer_context, lookup) if options.reinstall: if options.verbose: print("reinstall is true, resolving all dependencies") try: uninstalled, errors = lookup.resolve_all(packages, installer_context, implicit=options.recursive) except InvalidData as e: print("ERROR: unable to process all dependencies:\n\t%s"%(e), file=sys.stderr) return 1 else: uninstalled, errors = installer.get_uninstalled(packages, implicit=options.recursive, verbose=options.verbose) if options.verbose: print("uninstalled dependencies are: [%s]"%(', '.join([', '.join(pkg) for pkg in [v for k,v in uninstalled]]))) if errors: err_msg = ("ERROR: the following packages/stacks could not have their " "rosdep keys resolved\nto system dependencies") if rospkg.distro.current_distro_codename() is None: err_msg += ( " (ROS distro is not set. " "Make sure `ROS_DISTRO` environment variable is set, or use " "`--rosdistro` option to specify the distro, " "e.g. `--rosdistro indigo`)" ) print(err_msg + ":", file=sys.stderr) for rosdep_key, error in errors.items(): print("%s: %s"%(rosdep_key, error_to_human_readable(error)), file=sys.stderr) if options.robust: print("Continuing to install resolvable dependencies...") else: return 1 try: installer.install(uninstalled, **install_options) if not options.simulate: print("#All required rosdeps installed successfully") return 0 except KeyError as e: raise RosdepInternalError(e) except InstallFailed as e: print("ERROR: the following rosdeps failed to install", file=sys.stderr) print('\n'.join([" %s: %s"%(k, m) for k,m in e.failures]), file=sys.stderr) return 1 def _compute_depdb_output(lookup, packages, options): installer_context = create_default_installer_context(verbose=options.verbose) os_name, os_version = _detect_os(installer_context, options) output = "Rosdep dependencies for operating system %s version %s "%(os_name, os_version) for stack_name in stacks: output += "\nSTACK: %s\n"%(stack_name) view = lookup.get_stack_rosdep_view(stack_name) for rosdep in view.keys(): definition = view.lookup(rosdep) resolved = resolve_definition(definition, os_name, os_version) output = output + "<<<< %s -> %s >>>>\n"%(rosdep, resolved) return output def command_db(options): # exact same setup logic as command_resolve, should possibly combine lookup = _get_default_RosdepLookup(options) installer_context = create_default_installer_context(verbose=options.verbose) configure_installer_context(installer_context, options) os_name, os_version = installer_context.get_os_name_and_version() try: installer_keys = installer_context.get_os_installer_keys(os_name) default_key = installer_context.get_default_os_installer_key(os_name) except KeyError: raise UnsupportedOs(os_name, installer_context.get_os_keys()) installer = installer_context.get_installer(default_key) print("OS NAME: %s"%os_name) print("OS VERSION: %s"%os_version) errors = [] print("DB [key -> resolution]") # db does not leverage the resource-based API view = lookup.get_rosdep_view(DEFAULT_VIEW_KEY, verbose=options.verbose) for rosdep_name in view.keys(): try: d = view.lookup(rosdep_name) inst_key, rule = d.get_rule_for_platform(os_name, os_version, installer_keys, default_key) if options.filter_for_installers and inst_key not in options.filter_for_installers: continue resolved = installer.resolve(rule) resolved_str = " ".join(resolved) print ("%s -> %s"%(rosdep_name, resolved_str)) except ResolutionError as e: errors.append(e) #TODO: add command-line option for users to be able to see this. #This is useful for platform bringup, but useless for most users #as the rosdep db contains numerous, platform-specific keys. if 0: for error in errors: print("WARNING: %s"%(error_to_human_readable(error)), file=sys.stderr) def _print_lookup_errors(lookup): for error in lookup.get_errors(): if isinstance(error, rospkg.ResourceNotFound): print("WARNING: unable to locate resource %s"%(str(error.args[0])), file=sys.stderr) else: print("WARNING: %s"%(str(error)), file=sys.stderr) def command_what_needs(args, options): lookup = _get_default_RosdepLookup(options) packages = [] for rosdep_name in args: packages.extend(lookup.get_resources_that_need(rosdep_name)) _print_lookup_errors(lookup) print('\n'.join(set(packages))) def command_where_defined(args, options): lookup = _get_default_RosdepLookup(options) locations = [] for rosdep_name in args: locations.extend(lookup.get_views_that_define(rosdep_name)) _print_lookup_errors(lookup) if locations: for location in locations: origin = location[1] print(origin) else: print("ERROR: cannot find definition(s) for [%s]"%(', '.join(args)), file=sys.stderr) return 1 def command_resolve(args, options): lookup = _get_default_RosdepLookup(options) installer_context = create_default_installer_context(verbose=options.verbose) configure_installer_context(installer_context, options) installer, installer_keys, default_key, \ os_name, os_version = get_default_installer(installer_context=installer_context, verbose=options.verbose) invalid_key_errors = [] for rosdep_name in args: if len(args) > 1: print("#ROSDEP[%s]"%rosdep_name) view = lookup.get_rosdep_view(DEFAULT_VIEW_KEY, verbose=options.verbose) try: d = view.lookup(rosdep_name) except KeyError as e: invalid_key_errors.append(e) continue rule_installer, rule = d.get_rule_for_platform(os_name, os_version, installer_keys, default_key) installer = installer_context.get_installer(rule_installer) resolved = installer.resolve(rule) print("#%s"%(rule_installer)) print (" ".join([str(r) for r in resolved])) for error in invalid_key_errors: print("ERROR: no rosdep rule for %s"%(error), file=sys.stderr) for error in lookup.get_errors(): print("WARNING: %s"%(error_to_human_readable(error)), file=sys.stderr) if invalid_key_errors: return 1 # error exit code def command_fix_permissions(options): import os import pwd import grp stat_info = os.stat(os.path.expanduser('~')) uid = stat_info.st_uid gid = stat_info.st_gid user_name = pwd.getpwuid(uid).pw_name try: group_name = grp.getgrgid(gid).gr_name except KeyError as e: group_name = gid ros_home = rospkg.get_ros_home() print("Recursively changing ownership of ros home directory '{0}' " "to '{1}:{2}' (current user)...".format(ros_home, user_name, group_name)) failed = [] try: for dirpath, dirnames, filenames in os.walk(ros_home): try: os.lchown(dirpath, uid, gid) except Exception as e: failed.append((dirpath, str(e))) for f in filenames: try: path = os.path.join(dirpath, f) os.lchown(path, uid, gid) except Exception as e: failed.append((path, str(e))) except Exception: import traceback traceback.print_exc() print("Failed to walk directory. Try with sudo?") else: if failed: print("Failed to change ownership for:") for p, e in failed: print("{0} --> {1}".format(p, e)) print("Try with sudo?") else: print("Done.") command_handlers = { 'db': command_db, 'check': command_check, 'keys': command_keys, 'install': command_install, 'what-needs': command_what_needs, 'where-defined': command_where_defined, 'resolve': command_resolve, 'init': command_init, 'update': command_update, 'fix-permissions': command_fix_permissions, # backwards compat 'what_needs': command_what_needs, 'where_defined': command_where_defined, 'depdb': command_db, } # commands that accept rosdep names as args _command_rosdep_args = ['what-needs', 'what_needs', 'where-defined', 'where_defined', 'resolve'] # commands that take no args _command_no_args = ['update', 'init', 'db', 'fix-permissions'] _commands = command_handlers.keys() ros-rosdep-0.11.4/src/rosdep2/model.py000066400000000000000000000117431260171354700175250ustar00rootroot00000000000000# Copyright (c) 2011, 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 the 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. # Author Ken Conley/kwc@willowgarage.com """ Underlying model of rosdep data. The basic data model of rosdep is to store a dictionary of data indexed by view name (i.e. ROS stack name). This data includes a dictionary mapping rosdep dependency names to rules and the view dependencies. This is a lower-level representation. Higher-level representation can combine these rosdep dependency maps and view dependencies together into a combined view on which queries can be made. """ class RosdepDatabaseEntry(object): """ Stores rosdep data and metadata for a single view. """ def __init__(self, rosdep_data, view_dependencies, origin): """ :param rosdep_data: raw rosdep dictionary map for view :param view_dependencies: list of view dependency names :param origin: name of where data originated, e.g. filename """ assert isinstance(rosdep_data, dict), 'RosdepDatabaseEntry() rosdep_data is not a dict: %s' % rosdep_data self.rosdep_data = rosdep_data self.view_dependencies = view_dependencies self.origin = origin class RosdepDatabase(object): """ Stores loaded rosdep data for multiple views. """ def __init__(self): self._rosdep_db = {} # {view_name: RosdepDatabaseEntry} def is_loaded(self, view_name): """ :param view_name: name of view to check, ``str`` :returns: ``True`` if *view_name* has been loaded into this database. """ return view_name in self._rosdep_db def mark_loaded(self, view_name): """ If view is not already loaded, this will mark it as such. This in effect sets the data for the view to be empty. :param view_name: name of view to mark as loaded """ self.set_view_data(view_name, {}, [], None) def set_view_data(self, view_name, rosdep_data, view_dependencies, origin): """ Set data associated with view. This will create a new :class:`RosdepDatabaseEntry`. :param rosdep_data: rosdep data map to associated with view. This will be copied. :param origin: origin of view data, e.g. filepath of ``rosdep.yaml`` """ self._rosdep_db[view_name] = RosdepDatabaseEntry(rosdep_data.copy(), view_dependencies, origin) def get_view_names(self): """ :returns: list of view names that are loaded into this database. """ return self._rosdep_db.keys() def get_view_data(self, view_name): """ :returns: :class:`RosdepDatabaseEntry` of given view. :raises: :exc:`KeyError` if no entry for *view_name* """ return self._rosdep_db[view_name] def get_view_dependencies(self, view_name): """ :raises: :exc:`KeyError` if *view_name* is not an entry, or if all of view's dependencies have not been properly loaded. """ entry = self.get_view_data(view_name) dependencies = entry.view_dependencies[:] # compute full set of dependencies by iterating over # dependencies in reverse order and prepending. for s in reversed(entry.view_dependencies): dependencies = self.get_view_dependencies(s) + dependencies # make unique preserving order unique_deps = [] for d in dependencies: if not d in unique_deps: unique_deps.append(d) return unique_deps ros-rosdep-0.11.4/src/rosdep2/platforms/000077500000000000000000000000001260171354700200545ustar00rootroot00000000000000ros-rosdep-0.11.4/src/rosdep2/platforms/__init__.py000066400000000000000000000000001260171354700221530ustar00rootroot00000000000000ros-rosdep-0.11.4/src/rosdep2/platforms/arch.py000066400000000000000000000055041260171354700213470ustar00rootroot00000000000000#!/usr/bin/env python # Copyright (c) 2009, 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 the 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. # Author Tully Foote/tfoote@willowgarage.com import subprocess from ..installers import PackageManagerInstaller from .source import SOURCE_INSTALLER ARCH_OS_NAME = 'arch' PACMAN_INSTALLER = 'pacman' def register_installers(context): context.set_installer(PACMAN_INSTALLER, PacmanInstaller()) def register_platforms(context): context.add_os_installer_key(ARCH_OS_NAME, SOURCE_INSTALLER) context.add_os_installer_key(ARCH_OS_NAME, PACMAN_INSTALLER) context.set_default_os_installer_key(ARCH_OS_NAME, lambda self: PACMAN_INSTALLER) def pacman_detect_single(p): return not subprocess.call(['pacman', '-Q', p], stdout=subprocess.PIPE, stderr=subprocess.PIPE) def pacman_detect(packages): return [p for p in packages if pacman_detect_single(p)] class PacmanInstaller(PackageManagerInstaller): def __init__(self): super(PacmanInstaller, self).__init__(pacman_detect) def get_install_command(self, resolved, interactive=True, reinstall=False, quiet=False): #TODO: interactive switch packages = self.get_packages_to_install(resolved, reinstall=reinstall) if not packages: return [] else: return [self.elevate_priv(['pacman', '-Sy', '--needed', p]) for p in packages] ros-rosdep-0.11.4/src/rosdep2/platforms/cygwin.py000066400000000000000000000062361260171354700217350ustar00rootroot00000000000000#!/usr/bin/env python # Copyright (c) 2009, 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 the 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. # Tingfan Wu tingfan@gmail.com from __future__ import print_function from rospkg.os_detect import OS_CYGWIN from .source import SOURCE_INSTALLER from ..installers import PackageManagerInstaller from ..shell_utils import read_stdout APT_CYG_INSTALLER = 'apt-cyg' def register_installers(context): context.set_installer(APT_CYG_INSTALLER, AptCygInstaller()) def register_platforms(context): context.add_os_installer_key(OS_CYGWIN, SOURCE_INSTALLER) context.add_os_installer_key(OS_CYGWIN, APT_CYG_INSTALLER) context.set_default_os_installer_key(OS_CYGWIN, lambda self: APT_CYG_INSTALLER) def cygcheck_detect_single(p): std_out = read_stdout(['cygcheck', '-c', p]) return std_out.count("OK") > 0 def cygcheck_detect(packages): return [p for p in packages if cygcheck_detect_single(p)] class AptCygInstaller(PackageManagerInstaller): """ An implementation of the :class:`Installer` for use on cygwin-style systems. """ def __init__(self): super(AptCygInstaller, self).__init__(cygcheck_detect) self.as_root = False self.sudo_command = 'cygstart --action=runas' def get_install_command(self, resolved, interactive=True, reinstall=False, quiet=False): packages = self.get_packages_to_install(resolved, reinstall=reinstall) #TODO: interactive if not packages: return [] else: return [self.elevate_priv(['apt-cyg', '-m', 'ftp://sourceware.org/pub/cygwinports', 'install'])+packages] if __name__ == '__main__': print("test cygcheck_detect(true)", cygcheck_detect('cygwin')) ros-rosdep-0.11.4/src/rosdep2/platforms/debian.py000066400000000000000000000124731260171354700216570ustar00rootroot00000000000000#!/usr/bin/env python # Copyright (c) 2009, 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 the 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. # Author Tully Foote, Ken Conley from __future__ import print_function import sys from rospkg.os_detect import OS_DEBIAN, OS_LINARO, OS_UBUNTU, OsDetect from .pip import PIP_INSTALLER from .gem import GEM_INSTALLER from .source import SOURCE_INSTALLER from ..installers import PackageManagerInstaller from ..shell_utils import read_stdout # apt package manager key APT_INSTALLER='apt' def register_installers(context): context.set_installer(APT_INSTALLER, AptInstaller()) def register_platforms(context): register_debian(context) register_linaro(context) register_ubuntu(context) def register_debian(context): context.add_os_installer_key(OS_DEBIAN, APT_INSTALLER) context.add_os_installer_key(OS_DEBIAN, PIP_INSTALLER) context.add_os_installer_key(OS_DEBIAN, GEM_INSTALLER) context.add_os_installer_key(OS_DEBIAN, SOURCE_INSTALLER) context.set_default_os_installer_key(OS_DEBIAN, lambda self: APT_INSTALLER) context.set_os_version_type(OS_DEBIAN, OsDetect.get_codename) def register_linaro(context): # Linaro is an alias for Ubuntu. If linaro is detected and it's not set as an override force ubuntu. (os_name, os_version) = context.get_os_name_and_version() if os_name == OS_LINARO and not context.os_override: print("rosdep detected OS: [%s] aliasing it to: [%s]" % (OS_LINARO, OS_UBUNTU), file=sys.stderr) context.set_os_override(OS_UBUNTU, context.os_detect.get_codename()) def register_ubuntu(context): context.add_os_installer_key(OS_UBUNTU, APT_INSTALLER) context.add_os_installer_key(OS_UBUNTU, PIP_INSTALLER) context.add_os_installer_key(OS_UBUNTU, GEM_INSTALLER) context.add_os_installer_key(OS_UBUNTU, SOURCE_INSTALLER) context.set_default_os_installer_key(OS_UBUNTU, lambda self: APT_INSTALLER) context.set_os_version_type(OS_UBUNTU, OsDetect.get_codename) def dpkg_detect(pkgs, exec_fn=None): """ Given a list of package, return the list of installed packages. :param exec_fn: function to execute Popen and read stdout (for testing) """ ret_list = [] # this is mainly a hack to support version locking for eigen. # we strip version-locking syntax, e.g. libeigen3-dev=3.0.1-*. # our query does not do the validation on the version itself. version_lock_map = {} for p in pkgs: if '=' in p: version_lock_map[p.split('=')[0]] = p else: version_lock_map[p] = p cmd = ['dpkg-query', '-W', '-f=\'${Package} ${Status}\n\''] cmd.extend(version_lock_map.keys()) if exec_fn is None: exec_fn = read_stdout std_out = exec_fn(cmd) std_out = std_out.replace('\'','') pkg_list = std_out.split('\n') for pkg in pkg_list: pkg_row = pkg.split() if len(pkg_row) == 4 and (pkg_row[3] =='installed'): ret_list.append( pkg_row[0]) return [version_lock_map[r] for r in ret_list] class AptInstaller(PackageManagerInstaller): """ An implementation of the Installer for use on debian style systems. """ def __init__(self): super(AptInstaller, self).__init__(dpkg_detect) def get_install_command(self, resolved, interactive=True, reinstall=False, quiet=False): packages = self.get_packages_to_install(resolved, reinstall=reinstall) if not packages: return [] if not interactive and quiet: return [self.elevate_priv(['apt-get', 'install', '-y', '-qq', p]) for p in packages] elif quiet: return [self.elevate_priv(['apt-get', 'install', '-qq', p]) for p in packages] if not interactive: return [self.elevate_priv(['apt-get', 'install', '-y', p]) for p in packages] else: return [self.elevate_priv(['apt-get', 'install', p]) for p in packages] ros-rosdep-0.11.4/src/rosdep2/platforms/freebsd.py000066400000000000000000000070441260171354700220450ustar00rootroot00000000000000#!/usr/bin/env python # Copyright (c) 2010, 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 the 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. # Original from cygwin.py by Tingfan Wu tingfan@gmail.com # Modified for FreeBSD by Rene Ladan rene@freebsd.org import os import subprocess from rospkg.os_detect import OS_FREEBSD from .source import SOURCE_INSTALLER from ..installers import Installer PKG_ADD_INSTALLER = 'pkg_add' def register_installers(context): context.set_installer(PKG_ADD_INSTALLER, PkgAddInstaller()) def register_platforms(context): context.add_os_installer_key(OS_FREEBSD, SOURCE_INSTALLER) context.add_os_installer_key(OS_FREEBSD, PKG_ADD_INSTALLER) context.set_default_os_installer_key(OS_FREEBSD, lambda self: PKG_ADD_INSTALLER) def pkg_info_detect_single(p): if p == "builtin": return True # The next code is a lot of hassle, but there is no # better way in FreeBSD using just the base tools portname = p if p == "gtk20": portname = "gtk-2.\*" elif p == "py-gtk2": portname = "py27-gtk-2.\*" elif p[:9] in ["autoconf2", "automake1"]: portname = p[:8] + "-" + p[8] + "." + p[9:] + "\*" elif p[:3] == "py-": portname = "py27-" + p[3:] + "\*" else: portname = p + "-\*" pop = subprocess.Popen("/usr/sbin/pkg_info -qE " + portname, shell=True) return os.waitpid(pop.pid, 0)[1] == 0 # pkg_info -E returns 0 if pkg installed, 1 if not def pkg_info_detect(packages): return [p for p in packages if pkg_info_detect_single(p)] class PkgAddInstaller(Installer): """ An implementation of the Installer for use on FreeBSD-style systems. """ def __init__(self): super(PkgAddInstaller, self).__init__(pkg_info_detect) def get_install_command(self, resolved, interactive=True, reinstall=False, quiet=False): packages = self.get_packages_to_install(resolved, reinstall=reinstall) if not packages: return [] else: #pkg_add does not have a non-interactive command return [self.elevate_priv(['/usr/sbin/pkg_add', '-r'])+packages] ros-rosdep-0.11.4/src/rosdep2/platforms/gem.py000066400000000000000000000063731260171354700212070ustar00rootroot00000000000000#!/usr/bin/env python # Copyright (c) 2009, Willow Garage, Inc. # Copyright (c) 2012, Intermodalics, BVBA. # 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 the 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. # Author Ruben Smits/ruben.smits@intermodalics.eu from __future__ import print_function import subprocess from ..core import InstallFailed from ..installers import PackageManagerInstaller from ..shell_utils import read_stdout # gem package manager key GEM_INSTALLER = 'gem' def register_installers(context): context.set_installer(GEM_INSTALLER, GemInstaller()) def is_gem_installed(): try: subprocess.Popen(['gem'], stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate() return True except OSError: return False def gem_detect(pkgs, exec_fn=None): """ Given a list of package, return the list of installed packages. :param exec_fn: function to execute Popen and read stdout (for testing) """ if exec_fn is None: exec_fn = read_stdout pkg_list = exec_fn(['gem', 'list']).split('\n') ret_list = [] for pkg in pkg_list: pkg_row = pkg.split(" ") if pkg_row[0] in pkgs: ret_list.append( pkg_row[0]) return ret_list class GemInstaller(PackageManagerInstaller): """ :class:`Installer` support for gem. """ def __init__(self): super(GemInstaller, self).__init__(gem_detect, supports_depends=True) def get_install_command(self, resolved, interactive=True, reinstall=False, quiet=False): if not is_gem_installed(): raise InstallFailed((GEM_INSTALLER, "gem is not installed")) packages = self.get_packages_to_install(resolved, reinstall=reinstall) if not packages: return [] else: return [self.elevate_priv(['gem', 'install', p]) for p in packages] ros-rosdep-0.11.4/src/rosdep2/platforms/gentoo.py000066400000000000000000000112661260171354700217270ustar00rootroot00000000000000#!/usr/bin/env python # Copyright (c) 2009, 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 the 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. # # Author Murph Finnicum/murph@murph.cc ### A word on atoms ### # We'll be using 'atoms' instead of 'packages' for the majority of the gentoo installer. # Atoms can specify a package version (either exactly, or min/max version), flags it has # to be built with, and even repositories it has to come from # # Here are some valid atoms and their meanings: # sed // A package named 'sed' # sys-apps/sed // sed from the category 'sys-apps'. There can be collisions otherwise. # sys-apps/sed::gentoo // sed from the category 'sys-apps' and the repository 'gentoo' (the default). # >=sys-apps/sed-4 // sed of at least version 4 # sed[static,-nls] // sed built the static USE flag and withou the nls one import os from rospkg.os_detect import OS_GENTOO from .source import SOURCE_INSTALLER from ..installers import PackageManagerInstaller from ..shell_utils import read_stdout PORTAGE_INSTALLER = 'portage' def register_installers(context): context.set_installer(PORTAGE_INSTALLER, PortageInstaller()) def register_platforms(context): context.add_os_installer_key(OS_GENTOO, PORTAGE_INSTALLER) context.add_os_installer_key(OS_GENTOO, SOURCE_INSTALLER) context.set_default_os_installer_key(OS_GENTOO, lambda self: PORTAGE_INSTALLER) # Determine whether an atom is already satisfied def portage_detect_single(atom, exec_fn = read_stdout ): """ Check if a given atom is installed. :param exec_fn: function to execute Popen and read stdout (for testing) """ std_out = exec_fn(['portageq', 'match', '/', atom]) # TODO consdier checking the name of the package returned # Also, todo, figure out if just returning true if two packages are returned is cool.. return len(std_out) >= 1 def portage_detect(atoms, exec_fn = read_stdout): """ Given a list of atoms, return a list of which are already installed. :param exec_fn: function to execute Popen and read stdout (for testing) """ # This is for testing, to make sure they're always checked in the same order # TODO: make testing better to not need this if isinstance(atoms, list): atoms.sort() return [a for a in atoms if portage_detect_single(a, exec_fn)] # Check portage and needed tools for existence and compatibility def portage_available(): if not os.path.exists("/usr/bin/portageq"): return False if not os.path.exists("/usr/bin/emerge"): return False # We only use standard, defined portage features. # They work in all released versions of portage, and should work in # future versionf for a long time to come. # but .. TODO: Check versions return True class PortageInstaller(PackageManagerInstaller): def __init__(self): super(PortageInstaller, self).__init__(portage_detect) def get_install_command(self, resolved, interactive=True, reinstall=False, quiet=False): atoms = self.get_packages_to_install(resolved, reinstall=reinstall) cmd = self.elevate_priv(['emerge']) if not atoms: return [] if interactive: cmd.append('-a') cmd.extend(atoms) return [cmd] ros-rosdep-0.11.4/src/rosdep2/platforms/opensuse.py000066400000000000000000000056421260171354700222760ustar00rootroot00000000000000# Copyright (c) 2009, 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 the 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. # Author Tully Foote/tfoote@willowgarage.com import subprocess from rospkg.os_detect import OS_OPENSUSE from .source import SOURCE_INSTALLER from ..installers import PackageManagerInstaller # zypper package manager key ZYPPER_INSTALLER='zypper' def register_installers(context): context.set_installer(ZYPPER_INSTALLER, ZypperInstaller()) def register_platforms(context): context.add_os_installer_key(OS_OPENSUSE, SOURCE_INSTALLER) context.add_os_installer_key(OS_OPENSUSE, ZYPPER_INSTALLER) context.set_default_os_installer_key(OS_OPENSUSE, lambda self: ZYPPER_INSTALLER) def rpm_detect(packages): installed = [] for p in packages: if not subprocess.call(['rpm', '-q', p]): installed.append(p) return installed class ZypperInstaller(PackageManagerInstaller): """ This class provides the functions for installing using zypper. """ def __init__(self): super(ZypperInstaller, self).__init__(rpm_detect) def get_install_command(self, resolved, interactive=True, reinstall=False, quiet=False): packages = self.get_packages_to_install(resolved, reinstall=reinstall) if not packages: return [] if not interactive: return [self.elevate_priv(['zypper', 'install', '-yl'])+packages] else: return [self.elevate_priv(['zypper', 'install'])+packages] ros-rosdep-0.11.4/src/rosdep2/platforms/osx.py000066400000000000000000000314201260171354700212370ustar00rootroot00000000000000#!/usr/bin/env python # Copyright (c) 2009, 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 the 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. # Author Tully Foote/tfoote@willowgarage.com, Ken Conley import subprocess import json import sys import traceback from rospkg.os_detect import OS_OSX, OsDetect from ..core import InstallFailed, RosdepInternalError, InvalidData from .pip import PIP_INSTALLER from .source import SOURCE_INSTALLER from ..installers import PackageManagerInstaller from ..shell_utils import read_stdout # add additional os names for brew, macports (TODO) OSXBREW_OS_NAME = 'osxbrew' BREW_INSTALLER = 'homebrew' MACPORTS_INSTALLER = 'macports' #py3k try: _basestring = basestring except NameError: _basestring = str def register_installers(context): context.set_installer(MACPORTS_INSTALLER, MacportsInstaller()) context.set_installer(BREW_INSTALLER, HomebrewInstaller()) def register_platforms(context): context.add_os_installer_key(OS_OSX, BREW_INSTALLER) context.add_os_installer_key(OS_OSX, MACPORTS_INSTALLER) context.add_os_installer_key(OS_OSX, PIP_INSTALLER) context.add_os_installer_key(OS_OSX, SOURCE_INSTALLER) context.set_default_os_installer_key(OS_OSX, lambda self: BREW_INSTALLER) context.set_os_version_type(OS_OSX, OsDetect.get_codename) def is_port_installed(): try: subprocess.Popen(['port'], stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate() return True except OSError: return False def port_detect(pkgs, exec_fn=None): ret_list = [] if not is_port_installed(): return ret_list if exec_fn is None: exec_fn = read_stdout std_out = exec_fn(['port', 'installed']+pkgs) for pkg in std_out.split('\n'): pkg_row = pkg.split() if len(pkg_row) == 3 and pkg_row[0] in pkgs and pkg_row[2] =='(active)': ret_list.append(pkg_row[0]) return ret_list class MacportsInstaller(PackageManagerInstaller): """ An implementation of the :class:`Installer` API for use on macports systems. """ def __init__(self): super(MacportsInstaller, self).__init__(port_detect) def get_install_command(self, resolved, interactive=True, reinstall=False): if not is_port_installed(): raise InstallFailed((MACPORTS_INSTALLER, 'MacPorts is not installed')) packages = self.get_packages_to_install(resolved) if not packages: return [] else: #TODO: interactive return [self.elevate_priv(['port', 'install', p]) for p in packages] def is_brew_installed(): try: subprocess.Popen(['brew'], stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate() return True except OSError: return False class HomebrewResolution(object): """Resolution information for a single package of a Homebrew rosdep.""" def __init__(self, package, install_flags, options): """ :param package: Homebrew package name, possibly fully qualified with tap. :param install_flags: List of strings of additional flags for ``brew install`` and ``brew deps`` command which are not options (e.g. ``--HEAD``) :param options: List of strings of options for the homebrew package. """ self.package = package self.install_flags = install_flags self.options = options def __eq__(self, other): return other.package == self.package and \ other.install_flags == self.install_flags and \ other.options == self.options def __hash__(self): return hash(( type(self), self.package, tuple(self.install_flags), tuple(self.options))) def __str__(self): return ' '.join(self.to_list()) def to_list(self): return [self.package] + self.install_flags + self.options def brew_strip_pkg_name(package): """Strip the tap information of a fully qualified package name. :returns: Unqualified package name. E.g. 'foo-pkg' for input 'ros/hydro/foo-pkg' """ return package.split('/')[-1] def brew_detect(resolved, exec_fn=None): """Given a list of resolutions, return the list of installed resolutions. :param resolved: List of HomebrewResolution objects :returns: Filtered list of HomebrewResolution objects """ if exec_fn is None: exec_fn = read_stdout std_out = exec_fn(['brew', 'list']) installed_formulae = std_out.split() def is_installed(r): # TODO: Does not check installed version (stable, devel, HEAD) # TODO: Does not check origin (Tap) of formula # TODO: Does not handle excluding options (e.g. specifying # --without-foo for --with-foo option) # fast fail with a quick check first, then slower check if # really linked and for options if not brew_strip_pkg_name(r.package) in installed_formulae: return False std_out = exec_fn(['brew', 'info', r.package, '--json=v1']) try: pkg_info = json.loads(std_out) pkg_info = pkg_info[0] linked_version = pkg_info['linked_keg'] if not linked_version: return False for spec in pkg_info['installed']: if spec['version'] == linked_version: installed_options = spec['used_options'] break except (ValueError, TypeError): e_type, e, tb = sys.exc_info() raise RosdepInternalError( e, """Error while parsing brew info for '{0}' * Output of `brew info {0} --json=v1`: {1} * Error while parsing: {2}""".format(r.package, std_out, "".join(traceback.format_exception(e_type, e, tb)))) if set(r.options) <= set(installed_options): return True else: return False # preserve order return list(filter(is_installed, resolved)) class HomebrewInstaller(PackageManagerInstaller): """ An implementation of Installer for use on homebrew systems. Some examples for supported rosdep specifications: # Example 1: flat list of options if only one package defined. foo: osx: homebrew: depends: [bar] options: [--with-quux, --with-quax] packages: [foo-pkg] # Example 2: list of list of options for multiple packages bar: osx: homebrew: options: [[], [--with-quux]] packages: [bar-pkg, bar-pkg-dev] # Example 3: list of options can be shorter than list of packages (filling # up with empty options) baz: osx: homebrew: options: [[--with-quax]] packages: [baz-pkg, baz-pkg-dev] # Example 4: No options is fine. buz: osx: homebrew: packages: [buz-pkg] ``install_flags`` are handled analogously to ``options``. """ def __init__(self): super(HomebrewInstaller, self).__init__(brew_detect, supports_depends=True) self.as_root = False def resolve(self, rosdep_args): """ See :meth:`Installer.resolve()` """ def coerce_to_list(options): if isinstance(options, list): return options elif isinstance(options, _basestring): return options.split() else: raise InvalidData("Expected list or string for options '%s'" % options) def handle_options(options): # if only one package is specified we allow a flat list of options if len(packages) == 1 and options and not isinstance(options[0],list): options = [options] else: options = list(map(coerce_to_list, options)) # make sure options is a list of list of strings try: valid = all([isinstance(x, _basestring) for l in options for x in l]) except Exception as e: raise InvalidData("Invalid list of options '%s', error: %s" % (options, e)) else: if not valid: raise InvalidData("Invalid list of options '%s'" % options) # allow only fewer or equal number of option lists if len(options) > len(packages): raise InvalidData("More options '%s' than packages '%s'" % (options, packages)) else: options.extend([[]] * (len(packages) - len(options))) return options packages = super(HomebrewInstaller, self).resolve(rosdep_args) resolution = [] if packages: options = [] install_flags = [] if type(rosdep_args) == dict: options = coerce_to_list(rosdep_args.get("options", [])) install_flags = coerce_to_list(rosdep_args.get("install_flags", [])) options = handle_options(options) install_flags = handle_options(install_flags) # packages, options and install_flags now have the same length resolution = map(HomebrewResolution, packages, install_flags, options) return resolution def get_install_command(self, resolved, interactive=True, reinstall=False, quiet=False): # TODO: We should somehow inform the user that we uninstall all versions # of packages and do not keep track of which options have been # activated. Then again, maybe not this would be the # responsibility of the user to before or not use --reinstall. if not is_brew_installed(): raise InstallFailed((BREW_INSTALLER, 'Homebrew is not installed')) resolved = self.get_packages_to_install(resolved, reinstall=reinstall) resolved = self.remove_duplicate_dependencies(resolved) # interactive switch doesn't matter if reinstall: commands = [] for r in resolved: # --force uninstalls all versions of that package commands.append(self.elevate_priv(['brew', 'uninstall', '--force', r.package])) commands.append(self.elevate_priv(['brew', 'install'] + r.to_list())) return commands else: return [self.elevate_priv(['brew', 'install'] + r.to_list()) for r in resolved] def remove_duplicate_dependencies(self, resolved): # TODO: we do not look at options here, however the install check later # will inform use if installed options are not appropriate # TODO: we comapre unqualified package names, ignoring the specifed tap if not is_brew_installed(): raise InstallFailed((BREW_INSTALLER, 'Homebrew is not installed')) # we'll remove dependencies from this copy and return it resolved_copy = list(resolved) # find all dependencies for each package for r in resolved: sub_command = ['brew', 'deps'] + r.to_list() output = subprocess.Popen(sub_command, stdout=subprocess.PIPE).communicate()[0] deps = output.split() for d in deps: # remove duplicate dependency from package list for other in resolved_copy: if brew_strip_pkg_name(other.package) == brew_strip_pkg_name(d): resolved_copy.remove(other) return resolved_copy ros-rosdep-0.11.4/src/rosdep2/platforms/pip.py000066400000000000000000000100531260171354700212150ustar00rootroot00000000000000#!/usr/bin/env python # Copyright (c) 2009, 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 the 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. # Author Tully Foote/tfoote@willowgarage.com from __future__ import print_function import subprocess from ..core import InstallFailed from ..installers import PackageManagerInstaller from ..shell_utils import read_stdout # pip package manager key PIP_INSTALLER = 'pip' def register_installers(context): context.set_installer(PIP_INSTALLER, PipInstaller()) def is_pip_installed(): try: subprocess.Popen(['pip'], stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate() return True except OSError: return False def pip_detect(pkgs, exec_fn=None): """ Given a list of package, return the list of installed packages. :param exec_fn: function to execute Popen and read stdout (for testing) """ fallback_to_pip_show = False if exec_fn is None: exec_fn = read_stdout fallback_to_pip_show = True pkg_list = exec_fn(['pip', 'freeze']).split('\n') ret_list = [] for pkg in pkg_list: pkg_row = pkg.split("==") if pkg_row[0] in pkgs: ret_list.append(pkg_row[0]) # Try to detect with the return code of `pip show`. # This can show the existance of things like `argparse` which # otherwise do not show up. # See: # https://github.com/pypa/pip/issues/1570#issuecomment-71111030 if fallback_to_pip_show: for pkg in [p for p in pkgs if p not in ret_list]: # does not see retcode but stdout for old pip to check if installed proc = subprocess.Popen( ['pip', 'show', pkg], stdout=subprocess.PIPE, stderr=subprocess.STDOUT ) output, _ = proc.communicate() output = output.strip() if proc.returncode == 0 and output: # `pip show` detected it, add it to the list. ret_list.append(pkg) return ret_list class PipInstaller(PackageManagerInstaller): """ :class:`Installer` support for pip. """ def __init__(self): super(PipInstaller, self).__init__(pip_detect, supports_depends=True) def get_install_command(self, resolved, interactive=True, reinstall=False, quiet=False): if not is_pip_installed(): raise InstallFailed((PIP_INSTALLER, "pip is not installed")) packages = self.get_packages_to_install(resolved, reinstall=reinstall) if not packages: return [] else: return [self.elevate_priv(['pip', 'install', '-U', p]) for p in packages] ros-rosdep-0.11.4/src/rosdep2/platforms/redhat.py000066400000000000000000000153101260171354700216750ustar00rootroot00000000000000#!/usr/bin/env python # Copyright (c) 2009, 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 the 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. # Author Tully Foote/tfoote@willowgarage.com import subprocess from rospkg.os_detect import OS_RHEL, OS_FEDORA from .pip import PIP_INSTALLER from .source import SOURCE_INSTALLER from ..core import rd_debug from ..installers import PackageManagerInstaller from ..shell_utils import read_stdout # dnf package manager key DNF_INSTALLER='dnf' # yum package manager key YUM_INSTALLER='yum' def register_installers(context): context.set_installer(DNF_INSTALLER, DnfInstaller()) context.set_installer(YUM_INSTALLER, YumInstaller()) def register_platforms(context): register_fedora(context) register_rhel(context) def register_fedora(context): context.add_os_installer_key(OS_FEDORA, PIP_INSTALLER) context.add_os_installer_key(OS_FEDORA, DNF_INSTALLER) context.add_os_installer_key(OS_FEDORA, YUM_INSTALLER) context.add_os_installer_key(OS_FEDORA, SOURCE_INSTALLER) context.set_default_os_installer_key(OS_FEDORA, lambda self: DNF_INSTALLER if self.get_version().isdigit() and int(self.get_version()) > 21 else YUM_INSTALLER) context.set_os_version_type(OS_FEDORA, lambda self: self.get_version() if self.get_version().isdigit() and int(self.get_version()) > 20 else self.get_codename()) def register_rhel(context): context.add_os_installer_key(OS_RHEL, PIP_INSTALLER) context.add_os_installer_key(OS_RHEL, YUM_INSTALLER) context.add_os_installer_key(OS_RHEL, SOURCE_INSTALLER) context.set_default_os_installer_key(OS_RHEL, lambda self: YUM_INSTALLER) def rpm_detect_py(packages): ret_list = [] import rpm ts = rpm.TransactionSet() for raw_req in packages: req = rpm_expand_py(raw_req) rpms = ts.dbMatch(rpm.RPMTAG_PROVIDES, req) if len(rpms) > 0: ret_list += [raw_req] return ret_list def rpm_detect_cmd(raw_packages, exec_fn=None): ret_list = [] if exec_fn is None: exec_fn = read_stdout packages = [rpm_expand_cmd(package, exec_fn) for package in raw_packages] cmd = ['rpm', '-q', '--whatprovides', '--qf', '[%{PROVIDES}\n]'] cmd.extend(packages) std_out = exec_fn(cmd) out_lines = std_out.split() for index, package in enumerate(packages): if package in out_lines: ret_list.append(raw_packages[index]) return ret_list def rpm_detect(packages, exec_fn=None): try: return rpm_detect_py(packages) except ImportError: return rpm_detect_cmd(packages, exec_fn) def rpm_expand_py(macro): import rpm expanded = rpm.expandMacro(macro) rd_debug('Expanded rpm macro in \'%s\' to \'%s\'' % (macro, expanded)) return expanded def rpm_expand_cmd(macro, exec_fn=None): cmd = ['rpm', '-E', macro] if exec_fn is None: exec_fn = read_stdout expanded = exec_fn(cmd).strip() rd_debug('Expanded rpm macro in \'%s\' to \'%s\'' % (macro, expanded)) return expanded def rpm_expand(package, exec_fn=None): if not '%' in package: return package try: return rpm_expand_py(package) except ImportError: return rpm_expand_cmd(package, exec_fn) class DnfInstaller(PackageManagerInstaller): """ This class provides the functions for installing using dnf it's methods partially implement the Rosdep OS api to complement the roslib.OSDetect API. """ def __init__(self): super(DnfInstaller, self).__init__(rpm_detect) def get_install_command(self, resolved, interactive=True, reinstall=False, quiet=False): raw_packages = self.get_packages_to_install(resolved, reinstall=reinstall) packages = [rpm_expand(package) for package in raw_packages] if not packages: return [] elif not interactive and quiet: return [self.elevate_priv(['dnf', '--assumeyes', '--quiet', 'install']) + packages] elif quiet: return [self.elevate_priv(['dnf', '--quiet', 'install']) + packages] elif not interactive: return [self.elevate_priv(['dnf', '--assumeyes', 'install']) + packages] else: return [self.elevate_priv(['dnf', 'install']) + packages] class YumInstaller(PackageManagerInstaller): """ This class provides the functions for installing using yum it's methods partially implement the Rosdep OS api to complement the roslib.OSDetect API. """ def __init__(self): super(YumInstaller, self).__init__(rpm_detect) def get_install_command(self, resolved, interactive=True, reinstall=False, quiet=False): raw_packages = self.get_packages_to_install(resolved, reinstall=reinstall) packages = [rpm_expand(package) for package in raw_packages] if not packages: return [] elif not interactive and quiet: return [self.elevate_priv(['yum', '--assumeyes', '--quiet', '--skip-broken', 'install']) + packages] elif quiet: return [self.elevate_priv(['yum', '--quiet', '--skip-broken', 'install']) + packages] elif not interactive: return [self.elevate_priv(['yum', '--assumeyes', '--skip-broken', 'install']) + packages] else: return [self.elevate_priv(['yum', '--skip-broken', 'install']) + packages] ros-rosdep-0.11.4/src/rosdep2/platforms/source.py000066400000000000000000000262071260171354700217350ustar00rootroot00000000000000# Copyright (c) 2011, 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 the 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. # Author Tully Foote/tfoote@willowgarage.com from __future__ import print_function import os try: from urllib.request import urlopen from urllib.request import urlretrieve from urllib.error import URLError except ImportError: from urllib2 import urlopen from urllib import urlretrieve from urllib2 import URLError import hashlib import yaml from ..core import rd_debug, InvalidData from ..installers import PackageManagerInstaller, InstallFailed from ..shell_utils import create_tempfile_from_string_and_execute SOURCE_INSTALLER='source' def register_installers(context): context.set_installer(SOURCE_INSTALLER, SourceInstaller()) class InvalidRdmanifest(Exception): """ rdmanifest format is invalid. """ pass class DownloadFailed(Exception): """ File download failed either due to i/o issues or md5sum validation. """ pass def _sub_fetch_file(url, md5sum=None): """ Sub-routine of _fetch_file :raises: :exc:`DownloadFailed` """ contents = '' try: fh = urlopen(url) contents = fh.read() if md5sum is not None: filehash = hashlib.md5(contents).hexdigest() if md5sum and filehash != md5sum: raise DownloadFailed("md5sum didn't match for %s. Expected %s got %s"%(url, md5sum, filehash)) except URLError as ex: raise DownloadFailed(str(ex)) return contents def get_file_hash(filename): md5 = hashlib.md5() with open(filename,'rb') as f: for chunk in iter(lambda: f.read(8192), b''): md5.update(chunk) return md5.hexdigest() def fetch_file(url, md5sum=None): """ Download file. Optionally validate with md5sum :param url: URL to download :param md5sum: Expected MD5 sum of contents """ error = contents = '' try: contents = _sub_fetch_file(url, md5sum) if not isinstance(contents, str): contents = contents.decode('utf-8') except DownloadFailed as e: rd_debug("Download of file %s failed"%(url)) error = str(e) return contents, error def load_rdmanifest(contents): """ :raises: :exc:`InvalidRdmanifest` """ try: return yaml.load(contents) except yaml.scanner.ScannerError as ex: raise InvalidRdmanifest("Failed to parse yaml in %s: Error: %s"%(contents, ex)) def download_rdmanifest(url, md5sum, alt_url=None): """ :param url: URL to download rdmanifest from :param md5sum: MD5 sum for validating url download, or None :returns: (contents of rdmanifest, download_url). download_url is either *url* or *alt_url* and indicates which of the locations contents was generated from. :raises: :exc:`DownloadFailed` :raises: :exc:`InvalidRdmanifest` """ # fetch the manifest download_url = url error_prefix = "Failed to load a rdmanifest from %s: "%(url) contents, error = fetch_file(download_url, md5sum) # - try the backup url if not contents and alt_url: error_prefix = "Failed to load a rdmanifest from either %s or %s: "%(url, alt_url) download_url = alt_url contents, error = fetch_file(download_url, md5sum) if not contents: raise DownloadFailed(error_prefix + error) manifest = load_rdmanifest(contents) return manifest, download_url #TODO: create SourceInstall instance objects class SourceInstall(object): def __init__(self): self.manifest = self.manifest_url = None self.install_command = self.check_presence_command = None self.exec_path = None self.tarball = self.alternate_tarball = None self.tarball_md5sum = None self.dependencies = None @staticmethod def from_manifest(manifest, manifest_url): r = SourceInstall() r.manifest = manifest r.manifest_url = manifest_url rd_debug("Loading manifest:\n{{{%s\n}}}\n"%manifest) r.install_command = manifest.get("install-script", '') r.check_presence_command = manifest.get("check-presence-script", '') r.exec_path = manifest.get("exec-path", ".") try: r.tarball = manifest["uri"] except KeyError: raise InvalidRdmanifest("uri required for source rosdeps") r.alternate_tarball = manifest.get("alternate-uri") r.tarball_md5sum = manifest.get("md5sum") r.dependencies = manifest.get("depends", []) return r def __str__(self): return "source: %s"%(self.manifest_url) def is_source_installed(source_item, exec_fn=None): return create_tempfile_from_string_and_execute(source_item.check_presence_command, exec_fn=exec_fn) def source_detect(pkgs, exec_fn=None): return [x for x in pkgs if is_source_installed(x, exec_fn=exec_fn)] class SourceInstaller(PackageManagerInstaller): def __init__(self): super(SourceInstaller, self).__init__(source_detect, supports_depends=True) self._rdmanifest_cache = {} def resolve(self, rosdep_args): """ :raises: :exc:`InvalidData` If format invalid or unable to retrieve rdmanifests. :returns: [SourceInstall] instances. """ try: url = rosdep_args["uri"] except KeyError: raise InvalidData("'uri' key required for source rosdeps") alt_url = rosdep_args.get("alternate-uri", None) md5sum = rosdep_args.get("md5sum", None) # load manifest from cache or from web manifest = None if url in self._rdmanifest_cache: return self._rdmanifest_cache[url] elif alt_url in self._rdmanifest_cache: return self._rdmanifest_cache[alt_url] try: rd_debug("Downloading manifest [%s], mirror [%s]"%(url, alt_url)) manifest, download_url = download_rdmanifest(url, md5sum, alt_url) resolved = SourceInstall.from_manifest(manifest, download_url) self._rdmanifest_cache[download_url] = [resolved] return [resolved] except DownloadFailed as ex: # not sure this should be masked this way raise InvalidData(str(ex)) except InvalidRdmanifest as ex: raise InvalidData(str(ex)) def get_install_command(self, resolved, interactive=True, reinstall=False, quiet=False): # Instead of attempting to describe the source-install steps # inside of the rosdep command chain, we shell out to an # external rosdep-source command. This separation means that # users can manually invoke rosdep-source and also keeps # 'get_install_command()' cleaner. packages = self.get_packages_to_install(resolved, reinstall=reinstall) commands = [] for p in packages: commands.append(['rosdep-source', 'install', p.manifest_url]) return commands def get_depends(self, rosdep_args): deps = rosdep_args.get('depends', []) for r in self.resolve(rosdep_args): deps.extend(r.dependencies) return deps def install_from_file(rdmanifest_file): with open(rdmanifest_file, 'r') as f: contents = f.read() manifest = load_rdmanifest(contents) install_source(SourceInstall.from_manifest(manifest, rdmanifest_file)) def install_from_url(rdmanifest_url): manifest, download_url = download_rdmanifest(rdmanifest_url, None, None) install_source(SourceInstall.from_manifest(manifest, download_url)) def install_source(resolved): import shutil import tarfile import tempfile tempdir = tempfile.mkdtemp() rd_debug("created tmpdir [%s]"%(tempdir)) rd_debug("Fetching tarball %s"%resolved.tarball) # compute desired download path filename = os.path.join(tempdir, os.path.basename(resolved.tarball)) f = urlretrieve(resolved.tarball, filename) assert f[0] == filename if resolved.tarball_md5sum: rd_debug("checking md5sum on tarball") hash1 = get_file_hash(filename) if resolved.tarball_md5sum != hash1: #try backup tarball if it is defined if resolved.alternate_tarball: f = urlretrieve(resolved.alternate_tarball) filename = f[0] hash2 = get_file_hash(filename) if resolved.tarball_md5sum != hash2: failure = (SOURCE_INSTALLER, "md5sum check on %s and %s failed. Expected %s got %s and %s"%(resolved.tarball, resolved.alternate_tarball, resolved.tarball_md5sum, hash1, hash2)) raise InstallFailed(failure=failure) else: raise InstallFailed((SOURCE_INSTALLER, "md5sum check on %s failed. Expected %s got %s "%(resolved.tarball, resolved.tarball_md5sum, hash1))) else: rd_debug("No md5sum defined for tarball, not checking.") try: # This is a bit hacky. Basically, don't unpack dmg files as # we are currently using source rosdeps for Nvidia Cg. if not filename.endswith('.dmg'): rd_debug("Extracting tarball") tarf = tarfile.open(filename) tarf.extractall(tempdir) else: rd_debug("Bypassing tarball extraction as it is a dmg") rd_debug("Running installation script") success = create_tempfile_from_string_and_execute(resolved.install_command, os.path.join(tempdir, resolved.exec_path)) if success: rd_debug("successfully executed script") else: raise InstallFailed((SOURCE_INSTALLER, "installation script returned with error code")) finally: rd_debug("cleaning up tmpdir [%s]"%(tempdir)) shutil.rmtree(tempdir) ros-rosdep-0.11.4/src/rosdep2/rep3.py000066400000000000000000000062701260171354700172750ustar00rootroot00000000000000# 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 the 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. try: from urllib.request import urlopen except ImportError: from urllib2 import urlopen import yaml import warnings from .core import DownloadFailure from .rosdistrohelper import PreRep137Warning # location of targets file for processing gbpdistro files REP3_TARGETS_URL = 'https://raw.github.com/ros/rosdistro/master/releases/targets.yaml' #seconds to wait before aborting download of gbpdistro data DOWNLOAD_TIMEOUT = 15.0 def download_targets_data(targets_url=None): """ Download REP 3 targets file and unmarshal from YAML. DEPRECATED: this function is deprecated. List of targets should be obtained from the rosdistro module. The body of this function is an example. :param target_url: override URL of platform targets file. Defaults to ``REP3_TARGETS_URL``. :raises: :exc:`DownloadFailure` :raises: :exc:`InvalidData` If targets file does not pass cursory validation checks. """ warnings.warn("deprecated, use rosdistro instead", PreRep137Warning) if targets_url is None: targets_url = REP3_TARGETS_URL try: f = urlopen(targets_url, timeout=DOWNLOAD_TIMEOUT) text = f.read() f.close() targets_data = yaml.safe_load(text) except Exception as e: raise DownloadFailure("Failed to download target platform data for gbpdistro:\n\t%s"%(str(e))) if type(targets_data) == list: # convert to dictionary new_targets_data = {} for t in targets_data: platform = list(t.keys())[0] new_targets_data[platform] = t[platform] targets_data = new_targets_data return targets_data ros-rosdep-0.11.4/src/rosdep2/rosdistrohelper.py000066400000000000000000000056011260171354700216510ustar00rootroot00000000000000# Copyright (c) 2013, Open Source Robotics Foundation # 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 the 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. # Author Paul Mathieu/paul@osrfoundation.org import rosdistro class PreRep137Warning(UserWarning): pass class _RDCache: index_url = None index = None release_files = {} class ReleaseFile(object): def __init__(self, dist_file): self.repositories = {} for repo_name in dist_file.repositories.keys(): repo = dist_file.repositories[repo_name].release_repository if repo: self.repositories[repo_name] = repo self.platforms = dist_file.release_platforms def _check_cache(): if _RDCache.index_url != rosdistro.get_index_url(): _RDCache.index_url = rosdistro.get_index_url() _RDCache.index = None _RDCache.release_files = {} def get_index_url(): _check_cache() return _RDCache.index_url def get_index(): _check_cache() if _RDCache.index is None: _RDCache.index = rosdistro.get_index(_RDCache.index_url) return _RDCache.index def get_release_file(distro): _check_cache() if distro not in _RDCache.release_files: dist_file = rosdistro.get_distribution_file(get_index(), distro) _RDCache.release_files[distro] = ReleaseFile(dist_file) return _RDCache.release_files[distro] def get_targets(): return dict((d, get_release_file(d).platforms) for d in get_index().distributions) ros-rosdep-0.11.4/src/rosdep2/rospack.py000066400000000000000000000055301260171354700200640ustar00rootroot00000000000000# 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 the 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. # Author Dirk Thomas/dthomas@willowgarage.com """ API provided for rospack to determine if a dependency is a ROSpackage or a system dependency """ from __future__ import print_function import subprocess from .main import _get_default_RosdepLookup from .rospkg_loader import DEFAULT_VIEW_KEY from .sources_list import get_sources_cache_dir def call_pkg_config(option, pkg_name): try: value = subprocess.check_output(['pkg-config', option, pkg_name]) return value.strip() except subprocess.CalledProcessError: return None def init_rospack_interface(): class Options(object): def __init__(self): self.os_override = None self.sources_cache_dir = get_sources_cache_dir() self.verbose = False lookup = _get_default_RosdepLookup(Options()) return lookup.get_rosdep_view(DEFAULT_VIEW_KEY) def is_view_empty(view): return len(view.rosdep_defs) == 0 def is_ros_package(view, rosdep_name): return _ros_flag(view, rosdep_name, True) def is_system_dependency(view, rosdep_name): return _ros_flag(view, rosdep_name, False) def _ros_flag(view, rosdep_name, value): try: d = view.lookup(rosdep_name) except KeyError: return False ros_flag = '_is_ros' in d.data.keys() return ros_flag == value ros-rosdep-0.11.4/src/rosdep2/rospkg_loader.py000066400000000000000000000142021260171354700212510ustar00rootroot00000000000000# Copyright (c) 2011, 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 the 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. # Author Ken Conley/kwc@willowgarage.com """ Library for loading rosdep files from the ROS package/stack filesystem. """ from __future__ import print_function import catkin_pkg.package import rospkg from .loader import RosdepLoader # Default view key is the view that packages that are not in stacks # see. It is the root of all dependencies. It is superceded by an # explicit underlay_key. DEFAULT_VIEW_KEY='*default*' # Implementation details: this API was originally conceived under the # rosdep 1 design. It has since been retrofitted for the rosdep 2 # design, which means it is a bit overbuilt. There really is no need # for a notion of views for rospkg -- all rospkgs have the same view. # It we be nice to refactor this API into something much, much # simpler, which would probably involve merging RosPkgLoader and # SourcesListLoader. RosPkgLoader would provide identification of # resources and SourcesListLoader would build a *single* view that was # no longer resource-dependent. class RosPkgLoader(RosdepLoader): def __init__(self, rospack=None, rosstack=None, underlay_key=None): """ :param underlay_key: If set, all views loaded by this loader will depend on this key. """ if rospack is None: rospack = rospkg.RosPack() if rosstack is None: rosstack = rospkg.RosStack() self._rospack = rospack self._rosstack = rosstack self._rosdep_yaml_cache = {} self._underlay_key = underlay_key # cache computed list of loadable resources self._loadable_resource_cache = None def load_view(self, view_name, rosdep_db, verbose=False): """ Load view data into *rosdep_db*. If the view has already been loaded into *rosdep_db*, this method does nothing. If view has no rosdep data, it will be initialized with an empty data map. :raises: :exc:`InvalidData` if view rosdep.yaml is invalid :raises: :exc:`rospkg.ResourceNotFound` if view cannot be located :returns: ``True`` if view was loaded. ``False`` if view was already loaded. """ if rosdep_db.is_loaded(view_name): return if not view_name in self.get_loadable_views(): raise rospkg.ResourceNotFound(view_name) elif view_name == 'invalid': raise rospkg.ResourceNotFound("FOUND"+ view_name+str(self.get_loadable_views())) if verbose: print("loading view [%s] with rospkg loader"%(view_name)) # chain into underlay if set if self._underlay_key: view_dependencies = [self._underlay_key] else: view_dependencies = [] # no rospkg view has actual data rosdep_db.set_view_data(view_name, {}, view_dependencies, '') def get_loadable_views(self): """ 'Views' map to ROS stack names. """ return list(self._rosstack.list()) + [DEFAULT_VIEW_KEY] def get_loadable_resources(self): """ 'Resources' map to ROS packages names. """ if not self._loadable_resource_cache: self._loadable_resource_cache = list(self._rospack.list()) return self._loadable_resource_cache def get_rosdeps(self, resource_name, implicit=True): """ If *resource_name* is a stack, returns an empty list. :raises: :exc:`rospkg.ResourceNotFound` if *resource_name* cannot be found. """ if resource_name in self.get_loadable_resources(): m = self._rospack.get_manifest(resource_name) if m.is_catkin: path = self._rospack.get_path(resource_name) pkg = catkin_pkg.package.parse_package(path) deps = pkg.build_depends + pkg.buildtool_depends + pkg.run_depends + pkg.test_depends return [d.name for d in deps] else: return self._rospack.get_rosdeps(resource_name, implicit=implicit) elif resource_name in self._rosstack.list(): # stacks currently do not have rosdeps of their own, implicit or otherwise return [] else: raise rospkg.ResourceNotFound(resource_name) def get_view_key(self, resource_name): """ Map *resource_name* to a view key. In rospkg, this maps the DEFAULT_VIEW_KEY if *resource_name* exists. :raises: :exc:`rospkg.ResourceNotFound` """ if resource_name in self.get_loadable_resources(): return DEFAULT_VIEW_KEY else: raise rospkg.ResourceNotFound(resource_name) ros-rosdep-0.11.4/src/rosdep2/shell_utils.py000066400000000000000000000060751260171354700207560ustar00rootroot00000000000000# Copyright (c) 2009, 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 the 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. # Author Tully Foote/tfoote@willowgarage.com from __future__ import print_function import os import sys import stat import subprocess import tempfile from .core import rd_debug if sys.hexversion > 0x03000000: #Python3 python3 = True else: python3 = False def read_stdout(cmd): p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) std_out, std_err = p.communicate() if python3: return std_out.decode() else: return std_out def create_tempfile_from_string_and_execute(string_script, path=None, exec_fn=None): """ :param path: (optional) path to temp directory, or ``None`` to use default temp directory, ``str`` :param exec_fn: override subprocess.call with alternate executor (for testing) """ if path is None: path = tempfile.gettempdir() result = 1 try: fh = tempfile.NamedTemporaryFile('w', delete=False) fh.write(string_script) fh.close() print("Executing script below with cwd=%s\n{{{\n%s\n}}}\n"%(path, string_script)) try: os.chmod(fh.name, stat.S_IRWXU) if exec_fn is None: result = subprocess.call(fh.name, cwd=path) else: result = exec_fn(fh.name, cwd=path) except OSError as ex: print("Execution failed with OSError: %s"%(ex)) finally: if os.path.exists(fh.name): os.remove(fh.name) rd_debug("Return code was: %s"%(result)) return result == 0 ros-rosdep-0.11.4/src/rosdep2/sources_list.py000066400000000000000000000603561260171354700211470ustar00rootroot00000000000000# 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 the 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. # Author Ken Conley/kwc@willowgarage.com from __future__ import print_function import os import sys import tempfile import yaml import hashlib try: from urllib.request import urlopen from urllib.error import URLError except ImportError: from urllib2 import urlopen from urllib2 import URLError try: import cPickle as pickle except ImportError: import pickle from .core import InvalidData, DownloadFailure, CachePermissionError from .gbpdistro_support import get_gbprepo_as_rosdep_data, download_gbpdistro_as_rosdep_data try: import urlparse except ImportError: import urllib.parse as urlparse #py3k try: import httplib except ImportError: import http.client as httplib # py3k import rospkg import rospkg.distro from .loader import RosdepLoader from .rosdistrohelper import get_index, get_index_url # default file to download with 'init' command in order to bootstrap # rosdep DEFAULT_SOURCES_LIST_URL = 'https://raw.github.com/ros/rosdistro/master/rosdep/sources.list.d/20-default.list' #seconds to wait before aborting download of rosdep data DOWNLOAD_TIMEOUT = 15.0 SOURCES_LIST_DIR = 'sources.list.d' SOURCES_CACHE_DIR = 'sources.cache' # name of index file for sources cache CACHE_INDEX = 'index' # extension for binary cache PICKLE_CACHE_EXT = '.pickle' SOURCE_PATH_ENV = 'ROSDEP_SOURCE_PATH' def get_sources_list_dirs(source_list_dir): if SOURCE_PATH_ENV in os.environ: sdirs = os.environ[SOURCE_PATH_ENV].split(os.pathsep) else: sdirs = [source_list_dir] for p in list(sdirs): if not os.path.exists(p): sdirs.remove(p) return sdirs def get_sources_list_dir(): # base of where we read config files from # TODO: windows if 0: # we can't use etc/ros because environment config does not carry over under sudo etc_ros = rospkg.get_etc_ros_dir() else: etc_ros = '/etc/ros' # compute default system wide sources directory sys_sources_list_dir = os.path.join(etc_ros, 'rosdep', SOURCES_LIST_DIR) sources_list_dirs = get_sources_list_dirs(sys_sources_list_dir) if sources_list_dirs: return sources_list_dirs[0] else: return sys_sources_list_dir def get_default_sources_list_file(): return os.path.join(get_sources_list_dir(), '20-default.list') def get_sources_cache_dir(): ros_home = rospkg.get_ros_home() return os.path.join(ros_home, 'rosdep', SOURCES_CACHE_DIR) # Default rosdep.yaml format. For now this is the only valid type and # is specified for future compatibility. TYPE_YAML = 'yaml' # git-buildpackage repo list TYPE_GBPDISTRO = 'gbpdistro' VALID_TYPES = [TYPE_YAML, TYPE_GBPDISTRO] class DataSource(object): def __init__(self, type_, url, tags, origin=None): """ :param type_: data source type, e.g. TYPE_YAML, TYPE_GBPDISTRO :param url: URL of data location. For file resources, must start with the file:// scheme. For remote resources, URL must include a path. :param tags: tags for matching data source to configurations :param origin: filename or other indicator of where data came from for debugging. :raises: :exc:`ValueError` if parameters do not validate """ # validate inputs if not type_ in VALID_TYPES: raise ValueError("type must be one of [%s]"%(','.join(VALID_TYPES))) parsed = urlparse.urlparse(url) if not parsed.scheme or (parsed.scheme != 'file' and not parsed.netloc) or parsed.path in ('', '/'): raise ValueError("url must be a fully-specified URL with scheme, hostname, and path: %s"%(str(url))) if not type(tags) == list: raise ValueError("tags must be a list: %s"%(str(tags))) self.type = type_ self.tags = tags self.url = url self.origin = origin def __eq__(self, other): return isinstance(other, DataSource) and \ self.type == other.type and \ self.tags == other.tags and \ self.url == other.url and \ self.origin == other.origin def __str__(self): if self.origin: return "[%s]:\n%s %s %s"%(self.origin, self.type, self.url, ' '.join(self.tags)) else: return "%s %s %s"%(self.type, self.url, ' '.join(self.tags)) def __repr__(self): return repr((self.type, self.url, self.tags, self.origin)) class RosDistroSource(DataSource): def __init__(self, distro): self.type = TYPE_GBPDISTRO self.tags = [distro] # In this case self.url is a list if REP-143 is being used self.url = get_index().distributions[distro]['distribution'] self.origin = None # create function we can pass in as model to parse_source_data. The # function emulates the CachedDataSource constructor but does the # necessary full filepath calculation and loading of data. def cache_data_source_loader(sources_cache_dir, verbose=False): def create_model(type_, uri, tags, origin=None): # compute the filename has from the URL filename = compute_filename_hash(uri) filepath = os.path.join(sources_cache_dir, filename) pickle_filepath = filepath + PICKLE_CACHE_EXT if os.path.exists(pickle_filepath): if verbose: print("loading cached data source:\n\t%s\n\t%s"%(uri, pickle_filepath), file=sys.stderr) with open(pickle_filepath, 'rb') as f: rosdep_data = pickle.loads(f.read()) elif os.path.exists(filepath): if verbose: print("loading cached data source:\n\t%s\n\t%s"%(uri, filepath), file=sys.stderr) with open(filepath) as f: rosdep_data = yaml.load(f.read()) else: rosdep_data = {} return CachedDataSource(type_, uri, tags, rosdep_data, origin=filepath) return create_model class CachedDataSource(object): def __init__(self, type_, url, tags, rosdep_data, origin=None): """ Stores data source and loaded rosdep data for that source. NOTE: this is not a subclass of DataSource, though it's API is duck-type compatible with the DataSource API. """ self.source = DataSource(type_, url, tags, origin=origin) self.rosdep_data = rosdep_data def __eq__(self, other): try: return self.source == other.source and \ self.rosdep_data == other.rosdep_data except AttributeError: return False def __str__(self): return "%s\n%s"%(self.source, self.rosdep_data) def __repr__(self): return repr((self.type, self.url, self.tags, self.rosdep_data, self.origin)) @property def type(self): """ :returns: data source type """ return self.source.type @property def url(self): """ :returns: data source URL """ return self.source.url @property def tags(self): """ :returns: data source tags """ return self.source.tags @property def origin(self): """ :returns: data source origin, if set, or ``None`` """ return self.source.origin class DataSourceMatcher(object): def __init__(self, tags): self.tags = tags def matches(self, rosdep_data_source): """ Check if the datasource matches this configuration. :param rosdep_data_source: :class:`DataSource` """ # all of the rosdep_data_source tags must be in our matcher tags return not any(set(rosdep_data_source.tags)-set(self.tags)) @staticmethod def create_default(os_override=None): """ Create a :class:`DataSourceMatcher` to match the current configuration. :param os_override: (os_name, os_codename) tuple to override OS detection :returns: :class:`DataSourceMatcher` """ distro_name = rospkg.distro.current_distro_codename() if os_override is None: os_detect = rospkg.os_detect.OsDetect() os_name, os_version, os_codename = os_detect.detect_os() else: os_name, os_codename = os_override tags = [t for t in (distro_name, os_name, os_codename) if t] return DataSourceMatcher(tags) def download_rosdep_data(url): """ :raises: :exc:`DownloadFailure` If data cannot be retrieved (e.g. 404, bad YAML format, server down). """ try: f = urlopen(url, timeout=DOWNLOAD_TIMEOUT) text = f.read() f.close() data = yaml.safe_load(text) if type(data) != dict: raise DownloadFailure('rosdep data from [%s] is not a YAML dictionary'%(url)) return data except (URLError, httplib.HTTPException) as e: raise DownloadFailure(str(e) + ' (%s)' % url) except yaml.YAMLError as e: raise DownloadFailure(str(e)) def download_default_sources_list(url=DEFAULT_SOURCES_LIST_URL): """ Download (and validate) contents of default sources list. :param url: override URL of default sources list file :return: raw sources list data, ``str`` :raises: :exc:`InvalidData` :raises: :exc:`urllib2.URLError` If data cannot be retrieved (e.g. 404, server down). """ try: f = urlopen(url, timeout=DOWNLOAD_TIMEOUT) except (URLError, httplib.HTTPException) as e: raise URLError(str(e) + ' (%s)' % url) data = f.read().decode() f.close() if not data: raise RuntimeError("cannot download defaults file: empty contents") # parse just for validation parse_sources_data(data) return data def parse_sources_data(data, origin='', model=None): """ Parse sources file format (tags optional):: # comments and empty lines allowed [tags] e.g.:: yaml http://foo/rosdep.yaml fuerte lucid ubuntu If tags are specified, *all* tags must match the current configuration for the sources data to be used. :param data: data in sources file format :param model: model to load data into. Defaults to :class:`DataSource` :returns: List of data sources, [:class:`DataSource`] :raises: :exc:`InvalidData` """ if model is None: model = DataSource sources = [] for line in data.split('\n'): line = line.strip() # ignore empty lines or comments if not line or line.startswith('#'): continue splits = line.split(' ') if len(splits) < 2: raise InvalidData("invalid line:\n%s"%(line), origin=origin) type_ = splits[0] url = splits[1] tags = splits[2:] try: sources.append(model(type_, url, tags, origin=origin)) except ValueError as e: raise InvalidData("line:\n\t%s\n%s"%(line, e), origin=origin) return sources def parse_sources_file(filepath): """ Parse file on disk :returns: List of data sources, [:class:`DataSource`] :raises: :exc:`InvalidData` If any error occurs reading file, so an I/O error, non-existent file, or invalid format. """ try: with open(filepath, 'r') as f: return parse_sources_data(f.read(), origin=filepath) except IOError as e: raise InvalidData("I/O error reading sources file: %s"%(str(e)), origin=filepath) def parse_sources_list(sources_list_dir=None): """ Parse data stored in on-disk sources list directory into a list of :class:`DataSource` for processing. :returns: List of data sources, [:class:`DataSource`]. If there is no sources list dir, this returns an empty list. :raises: :exc:`InvalidData` :raises: :exc:`OSError` if *sources_list_dir* cannot be read. :raises: :exc:`IOError` if *sources_list_dir* cannot be read. """ if sources_list_dir is None: sources_list_dir = get_sources_list_dir() sources_list_dirs = get_sources_list_dirs(sources_list_dir) filelist = [] for sdir in sources_list_dirs: filelist += sorted([os.path.join(sdir, f) for f in os.listdir(sdir) if f.endswith('.list')]) sources_list = [] for f in filelist: sources_list.extend(parse_sources_file(f)) return sources_list def _generate_key_from_urls(urls): # urls may be a list of urls or a single string try: assert isinstance(urls, (list, basestring)) except NameError: assert isinstance(urls, (list, str)) # We join the urls by the '^' character because it is not allowed in urls return '^'.join(urls if isinstance(urls, list) else [urls]) def update_sources_list(sources_list_dir=None, sources_cache_dir=None, success_handler=None, error_handler=None): """ Re-downloaded data from remote sources and store in cache. Also update the cache index based on current sources. :param sources_list_dir: override source list directory :param sources_cache_dir: override sources cache directory :param success_handler: fn(DataSource) to call if a particular source loads successfully. This hook is mainly for printing errors to console. :param error_handler: fn(DataSource, DownloadFailure) to call if a particular source fails. This hook is mainly for printing errors to console. :returns: list of (`DataSource`, cache_file_path) pairs for cache files that were updated, ``[str]`` :raises: :exc:`InvalidData` If any of the sources list files is invalid :raises: :exc:`OSError` if *sources_list_dir* cannot be read. :raises: :exc:`IOError` If *sources_list_dir* cannot be read or cache data cannot be written """ if sources_cache_dir is None: sources_cache_dir = get_sources_cache_dir() sources = parse_sources_list(sources_list_dir=sources_list_dir) retval = [] for source in list(sources): try: if source.type == TYPE_YAML: rosdep_data = download_rosdep_data(source.url) elif source.type == TYPE_GBPDISTRO: # DEPRECATED, do not use this file. See REP137 if not source.tags[0] in ['electric', 'fuerte']: print('Ignore legacy gbpdistro "%s"' % source.tags[0]) sources.remove(source) continue # do not store this entry in the cache rosdep_data = download_gbpdistro_as_rosdep_data(source.url) retval.append((source, write_cache_file(sources_cache_dir, source.url, rosdep_data))) if success_handler is not None: success_handler(source) except DownloadFailure as e: if error_handler is not None: error_handler(source, e) # Additional sources for ros distros # In compliance with REP137 and REP143 print('Query rosdistro index %s' % get_index_url()) for dist_name in sorted(get_index().distributions.keys()): print('Add distro "%s"' % dist_name) rds = RosDistroSource(dist_name) rosdep_data = get_gbprepo_as_rosdep_data(dist_name) # dist_files can either be a string (single filename) or a list (list of filenames) dist_files = get_index().distributions[dist_name]['distribution'] key = _generate_key_from_urls(dist_files) retval.append((rds, write_cache_file(sources_cache_dir, key, rosdep_data))) sources.append(rds) # Create a combined index of *all* the sources. We do all the # sources regardless of failures because a cache from a previous # attempt may still exist. We have to do this cache index so that # loads() see consistent data. if not os.path.exists(sources_cache_dir): os.makedirs(sources_cache_dir) cache_index = os.path.join(sources_cache_dir, CACHE_INDEX) data = "#autogenerated by rosdep, do not edit. use 'rosdep update' instead\n" for source in sources: url = _generate_key_from_urls(source.url) data += "yaml %s %s\n" % (url, ' '.join(source.tags)) write_atomic(cache_index, data) # mainly for debugging and testing return retval def load_cached_sources_list(sources_cache_dir=None, verbose=False): """ Load cached data based on the sources list. :returns: list of :class:`CachedDataSource` instance with raw rosdep data loaded. :raises: :exc:`OSError` if cache cannot be read :raises: :exc:`IOError` if cache cannot be read """ if sources_cache_dir is None: sources_cache_dir = get_sources_cache_dir() cache_index = os.path.join(sources_cache_dir, 'index') if not os.path.exists(cache_index): if verbose: print("no cache index present, not loading cached sources", file=sys.stderr) return [] with open(cache_index, 'r') as f: cache_data = f.read() # the loader does all the work model = cache_data_source_loader(sources_cache_dir, verbose=verbose) return parse_sources_data(cache_data, origin=cache_index, model=model) def compute_filename_hash(key_filenames): sha_hash = hashlib.sha1() if isinstance(key_filenames, list): for key in key_filenames: sha_hash.update(key.encode()) else: sha_hash.update(key_filenames.encode()) return sha_hash.hexdigest() def write_cache_file(source_cache_d, key_filenames, rosdep_data): """ :param source_cache_d: directory to write cache file to :param key_filenames: filename (or list of filenames) to be used in hashing :param rosdep_data: dictionary of data to serialize as YAML :returns: name of file where cache is stored :raises: :exc:`OSError` if cannot write to cache file/directory :raises: :exc:`IOError` if cannot write to cache file/directory """ if not os.path.exists(source_cache_d): os.makedirs(source_cache_d) key_hash = compute_filename_hash(key_filenames) filepath = os.path.join(source_cache_d, key_hash) try: write_atomic(filepath + PICKLE_CACHE_EXT, pickle.dumps(rosdep_data, -1), True) except OSError as e: raise CachePermissionError("Failed to write cache file: " + str(e)) try: os.unlink(filepath) except OSError: pass return filepath def write_atomic(filepath, data, binary=False): # write data to new file fd, filepath_tmp = tempfile.mkstemp(prefix=os.path.basename(filepath) + '.tmp.', dir=os.path.dirname(filepath)) if (binary): fmode = 'wb' else: fmode = 'w' with os.fdopen(fd, fmode) as f: f.write(data) f.close() try: # switch file atomically (if supported) os.rename(filepath_tmp, filepath) except OSError: # fall back to non-atomic operation try: os.unlink(filepath) except OSError: pass try: os.rename(filepath_tmp, filepath) except OSError: os.unlink(filepath_tmp) class SourcesListLoader(RosdepLoader): """ SourcesList loader implements the general RosdepLoader API. This implementation is fairly simple as there is only one view the source list loader can create. It is also a bit degenerate as it is not capable of mapping resource names to views, thus any resource-name-based API fails or returns nothing interesting. This loader should not be used directly; instead, it is more useful composed with other higher-level implementations, like the :class:`rosdep2.rospkg_loader.RospkgLoader`. The general intent is to compose it with another loader by making all of the other loader's views depends on all the views in this loader. """ ALL_VIEW_KEY = 'sources.list' def __init__(self, sources): """ :param sources: cached sources list entries, [:class:`CachedDataSource`] """ self.sources = sources @staticmethod def create_default(matcher=None, sources_cache_dir=None, os_override=None, verbose=False): """ :param matcher: override DataSourceMatcher. Defaults to DataSourceMatcher.create_default(). :param sources_cache_dir: override location of sources cache """ if matcher is None: matcher = DataSourceMatcher.create_default(os_override=os_override) if verbose: print("using matcher with tags [%s]"%(', '.join(matcher.tags)), file=sys.stderr) sources = load_cached_sources_list(sources_cache_dir=sources_cache_dir, verbose=verbose) if verbose: print("loaded %s sources"%(len(sources)), file=sys.stderr) sources = [x for x in sources if matcher.matches(x)] if verbose: print("%s sources match current tags"%(len(sources)), file=sys.stderr) return SourcesListLoader(sources) def load_view(self, view_name, rosdep_db, verbose=False): """ Load view data into rosdep_db. If the view has already been loaded into rosdep_db, this method does nothing. :param view_name: name of ROS stack to load, ``str`` :param rosdep_db: database to load stack data into, :class:`RosdepDatabase` :raises: :exc:`InvalidData` """ if rosdep_db.is_loaded(view_name): return source = self.get_source(view_name) if verbose: print("loading view [%s] with sources.list loader"%(view_name), file=sys.stderr) view_dependencies = self.get_view_dependencies(view_name) rosdep_db.set_view_data(view_name, source.rosdep_data, view_dependencies, view_name) def get_loadable_resources(self): return [] def get_loadable_views(self): return [x.url for x in self.sources] def get_view_dependencies(self, view_name): # use dependencies to implement precedence if view_name != SourcesListLoader.ALL_VIEW_KEY: # if the view_name matches one of our sources, return # empty list as none of our sources has deps. if any([x for x in self.sources if view_name == x.url]): return [] # not one of our views, so it depends on everything we provide return [x.url for x in self.sources] def get_source(self, view_name): matches = [x for x in self.sources if x.url == view_name] if matches: return matches[0] else: raise rospkg.ResourceNotFound(view_name) def get_rosdeps(self, resource_name, implicit=True): """ Always raises as SourceListLoader defines no concrete resources with rosdeps. :raises: :exc:`rospkg.ResourceNotFound` """ raise rospkg.ResourceNotFound(resource_name) def get_view_key(self, resource_name): """ Always raises as SourceListLoader defines no concrete resources with rosdeps. :returns: Name of view that *resource_name* is in, ``None`` if no associated view. :raises: :exc:`rospkg.ResourceNotFound` if *resource_name* cannot be found. """ raise rospkg.ResourceNotFound(resource_name) ros-rosdep-0.11.4/stdeb.cfg000066400000000000000000000005531260171354700154650ustar00rootroot00000000000000[DEFAULT] Depends: python-rospkg (>= 1.0.34), python-yaml, python-catkin-pkg, python-rosdistro (>= 0.4.0) Depends3: python3-rospkg (>= 1.0.34), python3-yaml, python3-catkin-pkg, python3-rosdistro (>= 0.4.0) Conflicts: python3-rosdep Conflicts3: python-rosdep Suite: oneiric precise quantal raring saucy trusty utopic vivid wheezy jessie X-Python3-Version: >= 3.2 ros-rosdep-0.11.4/test/000077500000000000000000000000001260171354700146575ustar00rootroot00000000000000ros-rosdep-0.11.4/test/__init__.py000066400000000000000000000000001260171354700167560ustar00rootroot00000000000000ros-rosdep-0.11.4/test/debian/000077500000000000000000000000001260171354700161015ustar00rootroot00000000000000ros-rosdep-0.11.4/test/debian/dpkg-python-apt000066400000000000000000000000711260171354700210500ustar00rootroot00000000000000'apt install ok installed ''python install ok installed 'ros-rosdep-0.11.4/test/gem/000077500000000000000000000000001260171354700154275ustar00rootroot00000000000000ros-rosdep-0.11.4/test/gem/list_output000066400000000000000000000000711260171354700177430ustar00rootroot00000000000000json (1.7.5) nokogiri (1.5.5) rake (0.9.2.2) rdoc (3.12) ros-rosdep-0.11.4/test/osx/000077500000000000000000000000001260171354700154705ustar00rootroot00000000000000ros-rosdep-0.11.4/test/osx/brew-info-output000066400000000000000000000022071260171354700206420ustar00rootroot00000000000000subversion:[{"name":"subversion","homepage":"http://subversion.apache.org/","versions":{"stable":"1.8.8","bottle":true,"devel":null,"head":null},"revision":0,"installed":[{"version":"1.8.8","used_options":[],"built_as_bottle":null,"poured_from_bottle":true}],"linked_keg":"1.8.8","keg_only":false,"dependencies":["pkg-config","autoconf","automake","libtool","sqlite","scons","openssl"],"conflicts_with":[],"caveats":"svntools have been installed to:\n /usr/local/opt/subversion/libexec\n","options":[{"option":"--universal","description":"Build a universal binary"},{"option":"--java","description":"Build Java bindings"},{"option":"--perl","description":"Build Perl bindings"},{"option":"--ruby","description":"Build Ruby bindings"},{"option":"--with-python","description":"Build with python support"}]}] bazaar:[{"name":"bazaar","homepage":"http://bazaar-vcs.org/","versions":{"stable":"2.6.0","bottle":false,"devel":null,"head":null},"revision":0,"installed":[{"version":"2.6.0","used_options":[],"built_as_bottle":null,"poured_from_bottle":false}],"linked_keg":"2.6.0","keg_only":false,"dependencies":[],"conflicts_with":[],"caveats":null,"options":[]}] ros-rosdep-0.11.4/test/osx/brew-list-output000066400000000000000000000001461260171354700206620ustar00rootroot00000000000000bazaar boost cmake doxygen git jpeg libyaml little-cms log4cxx mr neon pil pkg-config subversion wget ros-rosdep-0.11.4/test/pip/000077500000000000000000000000001260171354700154475ustar00rootroot00000000000000ros-rosdep-0.11.4/test/pip/freeze_output000066400000000000000000000032111260171354700202670ustar00rootroot00000000000000Brlapi==0.5.4 ClientForm==0.2.10 CouchDB==0.6 GnuPGInterface==0.3.2 Jinja2==2.6 Mako==0.2.5 Numeric==24.2 PAM==0.4.2 PIL==1.1.7 PyBluez==0.18 PyChecker==0.8.18 PyOpenGL==3.0.0 PyYAML==3.09 Pygments==1.4 Pymacs==0.23 Pyste==0.9.10 ScientificPython==2.8 Sphinx==1.0.7 Twisted-Core==10.0.0 Twisted-Names==10.0.0 Twisted-Web==10.0.0 adium-theme-ubuntu==0.1 apturl==0.4.1ubuntu4.1 bzr==2.1.4 command-not-found==0.1 configglue==0.2dev configobj==4.7.1 coverage==3.5 cups==1.0 distribute==0.6.10 docutils==0.8 epydoc==3.0.1 fstab==1.4 gnome-app-install==0.4.2ubuntu2 hgview==1.1.3 httplib2==0.6.0 ipython==0.10 jockey==0.5.8 launchpadlib==1.6.0 lazr.restfulclient==0.9.11 lazr.uri==1.0.2 louis==1.7.0 lxml==2.2.4 matplotlib==0.99.1.1 mechanize==0.1.11 mercurial==1.4.3 mock==0.7.2 mod-python==3.3.1 nose==1.1.2 numpy==1.3.0 nvidia-common==0.0.0 oauth==1.0a onboard==0.93.0 papyon==0.4.8 paramiko==1.7.6 pexpect==2.3 protobuf==2.2.0 psycopg2==2.0.13 pyOpenSSL==0.10 pycrypto==2.0.1 pycurl==7.19.0 pygame==1.9.1release pygraphviz==0.99 pyinotify==0.8.9 pylibpcap==0.6.2 pyparsing==1.5.2 pyserial==2.3 python-apt==0.7.94.2ubuntu6.2 python-dateutil==1.4.1 python-debian==0.1.14ubuntu2 python-jenkins==0.2 pytz==2010b pyusb==0.4.2 pyxdg==0.18 rdflib==2.4.2 rosdep==0.1.0 rosinstall==0.5.21 rospkg==0.2.0 scapy==2.0.1 scipy==0.7.0 screen-resolution-extra==0.0.0 simplejson==2.0.9 smbc==1.0 speechd==0.3 speechd-config==0.0 system-service==0.1.6 ubuntuone-storage-protocol==1.2.0 ufw==0.30pre1-0ubuntu2 unattended-upgrades==0.1 usb-creator==0.2.22 vcstools==0.1.0 virtkey==0.01 wadllib==1.1.4 wsgiref==0.1.2 wxPython==2.8.10.1 wxPython-common==2.8.10.1 xkit==0.0.0 zope.interface==3.5.3 ros-rosdep-0.11.4/test/ros_home/000077500000000000000000000000001260171354700164725ustar00rootroot00000000000000ros-rosdep-0.11.4/test/ros_home/rosdep.yaml000066400000000000000000000074541260171354700206640ustar00rootroot00000000000000testassimp: ubuntu: apt: packages: [assimp-dev] debian: source: uri: 'https://kforge.ros.org/rosrelease/viewvc/sourcedeps/assimp/assimp-2.0.86-1.rdmanifest' md5sum: d5137302d8f00241ee10e623b97f9d22 osx: source: uri: 'https://kforge.ros.org/rosrelease/viewvc/sourcedeps/assimp/assimp-2.0.86-1.rdmanifest' md5sum: d5137302d8f00241ee10e623b97f9d22 testeigen: ubuntu: lucid: apt: packages: [libeigen3-dev=3.0.1-1+ros4~lucid] maverick: apt: packages: [libeigen3-dev=3.0.1-1+ros4~maverick] natty: apt: packages: [libeigen3-dev=3.0.1-1+ros4~natty] debian: source: uri: 'https://kforge.ros.org/rosrelease/viewvc/sourcedeps/eigen/eigen-3.0.1-1.rdmanifest' md5sum: 941db2fbb09d80c28426d335022fad95 osx: source: uri: 'https://kforge.ros.org/rosrelease/viewvc/sourcedeps/eigen/eigen-3.0.1-1.rdmanifest' md5sum: 941db2fbb09d80c28426d335022fad95 testyaml-cpp: ubuntu: apt: packages: [ yaml-cpp0.2.6-dev ] debian: source: uri: 'https://kforge.ros.org/rosrelease/viewvc/sourcedeps/yaml-cpp/yaml-cpp-0.2.5.rdmanifest' md5sum: f7fb81fd4a2fbd5022daa7686e816359 osx: source: uri: 'https://kforge.ros.org/rosrelease/viewvc/sourcedeps/yaml-cpp/yaml-cpp-cmake-0.2.5.rdmanifest' md5sum: 863fb3b7e5b5f1e22ff1365de6e66b34 testcheckinstall: ubuntu: apt: packages: [checkinstall] debian: apt: packages: [checkinstall] testcurl: ubuntu: libcurl4-openssl-dev debian: libcurl4-openssl-dev opensuse: libcurl-devel fedora: libcurl-devel arch: curl macports: curl gentoo: net-misc/curl freebsd: curl testlibxml2: ubuntu: libxml2-dev debian: libxml2-dev arch: libxml2 opensuse: libxml2-devel fedora: libxml2-devel macports: libxml2 gentoo: dev-libs/libxml2 freebsd: libxml2 fedora: libxml2-devel testcppunit: ubuntu: libcppunit-dev debian: libcppunit-dev opensuse: libcppunit-devel fedora: cppunit-devel rhel: cppunit-devel arch: cppunit macports: cppunit gentoo: dev-util/cppunit freebsd: cppunit testscons: ubuntu: scons debian: scons arch: scons opensuse: scons fedora: scons macports: scons gentoo: dev-util/scons freebsd: scons testlibxext: ubuntu: libxext-dev debian: libxext-dev opensuse: xorg-x11-libXext-devel fedora: libXext-devel rhel: libXext-devel macports: xorg-libXext arch: libxext gentoo: x11-libs/libXext freebsd: libXext testzziplib: ubuntu: libzzip-0-13 libzzip-dev debian: libzzip-0-13 libzzip-dev opensuse: zziplib-devel fedora: zziplib-devel rhel: zziplib-devel macports: libzzip arch: zziplib gentoo: dev-libs/zziplib freebsd: zziplib testlibxaw: ubuntu: libxaw7-dev debian: libxaw7-dev opensuse: xorg-x11-devel fedora: libXaw-devel rhel: libXaw-devel macports: xorg-libXaw arch: libxaw gentoo: x11-libs/libXaw freebsd: libXaw testopengl: ubuntu: libgl1-mesa-dev libglu1-mesa-dev debian: libgl1-mesa-dev libglu1-mesa-dev opensuse: Mesa-devel fedora: mesa-libGL-devel mesa-libGLU-devel rhel: mesa-libGL-devel mesa-libGLU-devel macports: mesa arch: mesa gentoo: media-libs/mesa freebsd: mesagl-mangled testlibxxf86vm: ubuntu: libxxf86vm-dev debian: libxxf86vm-dev opensuse: xorg-x11-devel fedora: libXxf86vm-devel rhel: libXxf86vm-devel macports: xorg-libXxf86vm arch: libxxf86vm gentoo: x11-libs/libXxf86vm freebsd: libXxf86vm testatlas: ubuntu: libatlas-base-dev debian: libatlas-base-dev fedora: atlas-devel arch: | macports: atlas gentoo: atlas testpython-sip4: ubuntu: python-sip4-dev sip4 debian: python-sip4-dev sip4 macports: py25-sip gentoo: dev-python/sip arch: sip testfestival: ubuntu: festival festvox-kallpc16k debian: festival festvox-kallpc16k arch: festival festival-kallpc16k ros-rosdep-0.11.4/test/rosdistro/000077500000000000000000000000001260171354700167075ustar00rootroot00000000000000ros-rosdep-0.11.4/test/rosdistro/index.yaml000066400000000000000000000002531260171354700207020ustar00rootroot00000000000000%YAML 1.1 # index file # this file describes the available ROS distributions # see REP 137: http://ros.org/reps/rep-0137.html --- type: index version: 2 distributions: [] ros-rosdep-0.11.4/test/source/000077500000000000000000000000001260171354700161575ustar00rootroot00000000000000ros-rosdep-0.11.4/test/source/foo.tar.gz000066400000000000000000000001741260171354700200730ustar00rootroot00000000000000PO1 0%'39,񍋵VZ_30L145e+IRE#5P3uON5kjm<޻ܭ%s~wv4(ros-rosdep-0.11.4/test/source/noop-installed.rdmanifest000066400000000000000000000003601260171354700231640ustar00rootroot00000000000000uri: 'https://yaml-cpp.googlecode.com/files/yaml-cpp-0.2.5.tar.gz' md5sum: b17dc36055cd2259c88b2602601415d9 install-script: | #!/bin/bash echo "noop" check-presence-script: | #!/bin/bash exit 0 exec-path: yaml-cpp-0.2.5 depends: [] ros-rosdep-0.11.4/test/source/noop-not-installed.rdmanifest000066400000000000000000000003601260171354700237620ustar00rootroot00000000000000uri: 'https://yaml-cpp.googlecode.com/files/yaml-cpp-0.2.5.tar.gz' md5sum: b17dc36055cd2259c88b2602601415d9 install-script: | #!/bin/bash echo "noop" check-presence-script: | #!/bin/bash exit 1 exec-path: yaml-cpp-0.2.5 depends: [] ros-rosdep-0.11.4/test/source/rep112-example.rdmanifest000066400000000000000000000011131260171354700226740ustar00rootroot00000000000000uri: 'https://yaml-cpp.googlecode.com/files/yaml-cpp-0.2.5.tar.gz' md5sum: b17dc36055cd2259c88b2602601415d9 install-script: | #!/bin/bash set -o errexit mkdir -p build cd build cmake .. make echo "About to run checkinstall make install" sudo checkinstall -y --nodoc --pkgname=yaml-cpp-sourcedep make install check-presence-script: | #!/bin/bash dpkg-query -W -f='${Package} ${Status}\n' yaml-cpp-sourcedep | awk '{\ if ($4 =="installed") exit 0 else print "yaml-cpp-sourcedep not installed" exit 1}' exec-path: yaml-cpp-0.2.5 depends: [checkinstall ] ros-rosdep-0.11.4/test/sources.list.d/000077500000000000000000000000001260171354700175365ustar00rootroot00000000000000ros-rosdep-0.11.4/test/sources.list.d/20-default.list000066400000000000000000000003111260171354700222710ustar00rootroot00000000000000yaml https://github.com/ros/rosdistro/raw/master/rosdep/base.yaml # for test data, give this a tag so we can validate matcher yaml https://github.com/ros/rosdistro/raw/master/rosdep/python.yaml python ros-rosdep-0.11.4/test/sources.list.d/30-nonexistent.list000066400000000000000000000000751260171354700232330ustar00rootroot00000000000000yaml https://badhostname.willowgarage.com/rosdep.yaml ubuntu ros-rosdep-0.11.4/test/sources_cache/000077500000000000000000000000001260171354700174655ustar00rootroot00000000000000ros-rosdep-0.11.4/test/sources_cache/0a12d6e7b0d47be9b76e7726720e4cb79528cbaa000066400000000000000000000057571260171354700251470ustar00rootroot00000000000000testboost: arch: boost cygwin: libboost-devel libboost1.40 debian: {lenny: "if [ ! -f /opt/ros/lib/libboost_date_time-gcc43-mt*-1_37.a ] ;\ \ then\n mkdir -p ~/ros/ros-deps\n cd ~/ros/ros-deps\n wget --tries=10 http://pr.willowgarage.com/downloads/boost_1_37_0.tar.gz\n\ \ tar xzf boost_1_37_0.tar.gz\n cd boost_1_37_0\n ./configure --prefix=/opt/ros\n\ \ make\n sudo make install\nfi\n", squeeze: libboost1.42-all-dev} fedora: boost-devel freebsd: boost-python-libs gentoo: dev-libs/boost macports: boost opensuse: boost-devel osxbrew: homebrew: packages: [boost] rhel: boost-devel ubuntu: lucid: apt: packages: [libboost1.40-all-dev] maverick: apt: packages: [libboost1.42-all-dev] natty: apt: packages: [libboost1.42-all-dev] oneiric: apt: packages: [libboost1.46-all-dev] bzip2: arch: bzip2 cygwin: bzip2 debian: libbz2-dev fedora: bzip2-devel freebsd: bzip2 gentoo: app-arch/bzip2 macports: bzip2 opensuse: libbz2-devel osxbrew: homebrew: {packages: ''} rhel: bzip2-devel ubuntu: libbz2-dev checkinstall: debian: apt: packages: [checkinstall] osxbrew: homebrew: {packages: ''} ubuntu: apt: packages: [checkinstall] cmake: {ubuntu: cmake} cppunit: arch: cppunit debian: libcppunit-dev fedora: cppunit-devel freebsd: cppunit gentoo: dev-util/cppunit macports: cppunit opensuse: libcppunit-devel osxbrew: homebrew: args: [--universal] packages: [cppunit] rhel: cppunit-devel ubuntu: libcppunit-dev curl: arch: curl debian: libcurl4-openssl-dev fedora: libcurl-devel freebsd: curl gentoo: net-misc/curl macports: curl opensuse: libcurl-devel osxbrew: homebrew: {packages: ''} ubuntu: libcurl4-openssl-dev eigen: debian: source: {md5sum: 941db2fbb09d80c28426d335022fad95, uri: 'https://kforge.ros.org/rosrelease/viewvc/sourcedeps/eigen/eigen-3.0.1-1.rdmanifest'} gentoo: '>=dev-cpp/eigen-3' osxbrew: homebrew: packages: [eigen] ubuntu: apt: packages: [libeigen3-dev] epydoc: debian: python-epydoc fedora: epydoc freebsd: epydoc gentoo: dev-python/epydoc macports: py26-epydoc osxbrew: lion: pip: packages: [epydoc] ubuntu: python-epydoc festival: {arch: festival festival-kallpc16k, debian: festival festvox-kallpc16k, ubuntu: festival festvox-kallpc16k} testlibtool: arch: libtool debian: {lenny: libtool libltdl3-dev, squeeze: libtool libltdl-dev} fedora: libtool libtool-ltdl-devel freebsd: libtool gentoo: sys-devel/libtool macports: libtool opensuse: libtool libltdl3 osxbrew: homebrew: {packages: ''} rhel: libtool libtool-ltdl-devel ubuntu: apt: packages: [libtool, libltdl-dev] testtinyxml: debian: libtinyxml-dev fedora: tinyxml-devel osxbrew: homebrew: formula_uri: https://kforge.ros.org/rososx/homebrew/file/tip/electric/tinyxml.rb packages: [tinyxml] ubuntu: libtinyxml-dev ros-rosdep-0.11.4/test/sources_cache/82cbc7008b5117bcc6ce794832659e4f7763d2db000066400000000000000000000062701260171354700250120ustar00rootroot00000000000000actionlib: ubuntu: lucid: apt: packages: [ros-fuerte-actionlib] oneiric: apt: packages: [ros-fuerte-actionlib] catkin: ubuntu: lucid: apt: packages: [ros-fuerte-catkin] oneiric: apt: packages: [ros-fuerte-catkin] common_msgs: ubuntu: lucid: apt: packages: [ros-fuerte-common-msgs] oneiric: apt: packages: [ros-fuerte-common-msgs] flann: ubuntu: lucid: apt: packages: [ros-fuerte-flann] oneiric: apt: packages: [ros-fuerte-flann] gencpp: ubuntu: lucid: apt: packages: [ros-fuerte-gencpp] oneiric: apt: packages: [ros-fuerte-gencpp] genlisp: ubuntu: lucid: apt: packages: [ros-fuerte-genlisp] oneiric: apt: packages: [ros-fuerte-genlisp] genmsg: ubuntu: lucid: apt: packages: [ros-fuerte-genmsg] oneiric: apt: packages: [ros-fuerte-genmsg] genpy: ubuntu: lucid: apt: packages: [ros-fuerte-genpy] oneiric: apt: packages: [ros-fuerte-genpy] langs: ubuntu: lucid: apt: packages: [ros-fuerte-langs] oneiric: apt: packages: [ros-fuerte-langs] octomap: ubuntu: lucid: apt: packages: [ros-fuerte-octomap] oneiric: apt: packages: [ros-fuerte-octomap] ompl: ubuntu: lucid: apt: packages: [ros-fuerte-ompl] oneiric: apt: packages: [ros-fuerte-ompl] opencv2: ubuntu: lucid: apt: packages: [ros-fuerte-opencv2] oneiric: apt: packages: [ros-fuerte-opencv2] pcl: ubuntu: lucid: apt: packages: [ros-fuerte-pcl] oneiric: apt: packages: [ros-fuerte-pcl] ros: ubuntu: lucid: apt: packages: [ros-fuerte-ros] oneiric: apt: packages: [ros-fuerte-ros] ros_comm: ubuntu: lucid: apt: packages: [ros-fuerte-ros-comm] oneiric: apt: packages: [ros-fuerte-ros-comm] ros_tutorials: ubuntu: lucid: apt: packages: [ros-fuerte-ros-tutorials] oneiric: apt: packages: [ros-fuerte-ros-tutorials] roscpp_core: ubuntu: lucid: apt: packages: [ros-fuerte-roscpp-core] oneiric: apt: packages: [ros-fuerte-roscpp-core] rospack: ubuntu: lucid: apt: packages: [ros-fuerte-rospack] oneiric: apt: packages: [ros-fuerte-rospack] rospkg: ubuntu: lucid: apt: packages: [ros-fuerte-rospkg] oneiric: apt: packages: [ros-fuerte-rospkg] rx: ubuntu: lucid: apt: packages: [ros-fuerte-rx] oneiric: apt: packages: [ros-fuerte-rx] sbpl: ubuntu: lucid: apt: packages: [ros-fuerte-sbpl] oneiric: apt: packages: [ros-fuerte-sbpl] std_msgs: ubuntu: lucid: apt: packages: [ros-fuerte-std-msgs] oneiric: apt: packages: [ros-fuerte-std-msgs] swig-wx: ubuntu: lucid: apt: packages: [ros-fuerte-swig-wx] oneiric: apt: packages: [ros-fuerte-swig-wx] ros-rosdep-0.11.4/test/sources_cache/f6f4ef95664e373cd4754501337fa217f5b55d91000066400000000000000000000021601260171354700246530ustar00rootroot00000000000000paramiko: arch: python-paramiko debian: python-paramiko fedora: python-paramiko freebsd: py27-paramiko gentoo: dev-python/paramiko macports: py26-paramiko opensuse: python-paramiko ubuntu: python-paramiko testpython: arch: python cygwin: python debian: python-dev fedora: python-devel freebsd: python gentoo: python opensuse: python-devel rhel: python-devel ubuntu: python-dev osx: homebrew: packages: [] python-empy: {ubuntu: python-empy} python-gtk2: arch: pygtk debian: python-gtk2 fedora: pygtk2 freebsd: py-gtk2 gentoo: =dev-python/pygtk-2* opensuse: python-gtk pip: pygtk rhel: pygtk2 ubuntu: python-gtk2 python-imaging: arch: python-imaging debian: python-imaging fedora: python-imaging freebsd: py27-imaging gentoo: dev-python/imaging opensuse: python-imaging rhel: python-imaging ubuntu: python-imaging python-matplotlib: arch: python-matplotlib debian: python-matplotlib fedora: python-matplotlib freebsd: py27-matplotlib gentoo: dev-python/matplotlib opensuse: python-matplotlib rhel: python-matplotlib ubuntu: python-matplotlib ros-rosdep-0.11.4/test/sources_cache/index000066400000000000000000000004301260171354700205140ustar00rootroot00000000000000#autogenerated by rosdep, do not edit. use 'rosdep update' instead yaml https://github.com/ros/rosdistro/raw/master/rosdep/base.yaml yaml https://github.com/ros/rosdistro/raw/master/rosdep/python.yaml yaml https://github.com/ros/rosdistro/raw/master/releases/fuerte.yaml fuerte ros-rosdep-0.11.4/test/test_rosdep.py000066400000000000000000000044501260171354700175670ustar00rootroot00000000000000# Copyright (c) 2011, 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 the 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. from __future__ import print_function import os import sys def test_create_default_installer_context(): import rosdep2 # test both constructors for context in [rosdep2.create_default_installer_context(), rosdep2.create_default_installer_context(verbose=True)]: assert context is not None assert isinstance(context, rosdep2.InstallerContext) #this is just tripwire as we actual value will change over time from rospkg.os_detect import OS_UBUNTU, OsDetect assert OS_UBUNTU in context.get_os_keys() assert context.get_installer('apt') is not None assert 'apt' in context.get_os_installer_keys(OS_UBUNTU) assert OsDetect.get_codename == context.get_os_version_type(OS_UBUNTU) ros-rosdep-0.11.4/test/test_rosdep_arch.py000066400000000000000000000053671260171354700205740ustar00rootroot00000000000000# Copyright (c) 2011, 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 the 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. # Author Ken Conley/kwc@willowgarage.com import os import traceback from mock import Mock, patch def get_test_dir(): # not used yet return os.path.abspath(os.path.join(os.path.dirname(__file__), 'arch')) def test_PacmanInstaller(): from rosdep2.platforms.arch import PacmanInstaller @patch.object(PacmanInstaller, 'get_packages_to_install') def test(mock_method): installer = PacmanInstaller() mock_method.return_value = [] assert [] == installer.get_install_command(['fake']) # no interactive option implemented yet mock_method.return_value = ['a', 'b'] expected = [['sudo', '-H', 'pacman', '-Sy', '--needed', 'a'], ['sudo', '-H', 'pacman', '-Sy', '--needed', 'b']] val = installer.get_install_command(['whatever'], interactive=False) assert val == expected, val expected = [['sudo', '-H', 'pacman', '-Sy', '--needed', 'a'], ['sudo', '-H', 'pacman', '-Sy', '--needed', 'b']] val = installer.get_install_command(['whatever'], interactive=True) assert val == expected, val try: test() except AssertionError: traceback.print_exc() raise ros-rosdep-0.11.4/test/test_rosdep_catkin_packages.py000066400000000000000000000020761260171354700227600ustar00rootroot00000000000000import contextlib import os import tempfile from rosdep2.catkin_packages import find_catkin_packages_in @contextlib.contextmanager def directory(path): cwd = os.getcwd() os.chdir(path) yield os.chdir(cwd) def create_package_xml(path, version='0.1.0'): path = os.path.abspath(path) os.makedirs(path) template = """\ {0} {1} Package {0} BSD Foo Bar """.format(path.split('/')[-1], version) with open(os.path.join(path, 'package.xml'), 'w+') as f: f.write(template) def test_find_catkin_packages_in(): tmp_dir = tempfile.mkdtemp() with directory(tmp_dir): create_package_xml('src/foo', '0.2.0') create_package_xml('src/bar', '0.3.0') create_package_xml('src/baz', '0.2.0') pkgs = find_catkin_packages_in('src') assert sorted(pkgs) == sorted(['foo', 'bar', 'baz']), \ 'actually: ' + str(sorted(pkgs)) ros-rosdep-0.11.4/test/test_rosdep_catkin_support.py000066400000000000000000000012071260171354700227110ustar00rootroot00000000000000from rosdep2.catkin_support import get_installer, get_catkin_view, ValidationFailed, resolve_for_os from rosdep2.platforms.debian import APT_INSTALLER def test_workflow(): try: installer = get_installer(APT_INSTALLER) view = get_catkin_view('fuerte', 'ubuntu', 'lucid') resolved = resolve_for_os('cmake', view, installer, 'ubuntu', 'lucid') assert ['cmake'] == resolved resolved = resolve_for_os('python', view, installer, 'ubuntu', 'lucid') assert resolved == ['python-dev'] except ValidationFailed: # tests fail on the server because 'rosdep init' has not been run pass ros-rosdep-0.11.4/test/test_rosdep_core.py000066400000000000000000000041451260171354700206000ustar00rootroot00000000000000# Copyright (c) 2011, 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 the 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. import os def test_RosdepInternalError(): from rosdep2.core import RosdepInternalError try: raise Exception('foo') except Exception as e: ex = RosdepInternalError(e) assert e == ex.error def test_rd_debug(): # just tripwire/coverage from rosdep2.core import rd_debug rd_debug('foo') os.environ['ROSDEP_DEBUG'] = '1' rd_debug('foo') def test_InvalidData(): from rosdep2.core import InvalidData try: raise InvalidData('hi') except InvalidData as ex: assert 'hi' in str(ex) ros-rosdep-0.11.4/test/test_rosdep_cygwin.py000066400000000000000000000052451260171354700211520ustar00rootroot00000000000000# Copyright (c) 2011, 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 the 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. # Author Ken Conley/kwc@willowgarage.com import os import traceback from mock import patch def get_test_dir(): # not used yet return os.path.abspath(os.path.join(os.path.dirname(__file__), 'cygwin')) def test_AptCygInstaller(): from rosdep2.platforms.cygwin import AptCygInstaller @patch.object(AptCygInstaller, 'get_packages_to_install') def test(mock_method): installer = AptCygInstaller() mock_method.return_value = [] assert [] == installer.get_install_command(['fake']) # no interactive option implemented yet mock_method.return_value = ['a', 'b'] expected = [['apt-cyg', '-m', 'ftp://sourceware.org/pub/cygwinports', 'install', 'a', 'b']] val = installer.get_install_command(['whatever'], interactive=False) assert val == expected, val expected = [['apt-cyg', '-m', 'ftp://sourceware.org/pub/cygwinports', 'install', 'a', 'b']] val = installer.get_install_command(['whatever'], interactive=True) assert val == expected, val try: test() except AssertionError: traceback.print_exc() raise ros-rosdep-0.11.4/test/test_rosdep_debian.py000066400000000000000000000066601260171354700210760ustar00rootroot00000000000000# Copyright (c) 2011, 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 the 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. # Author Ken Conley/kwc@willowgarage.com import os import traceback from mock import Mock, patch def get_test_dir(): return os.path.abspath(os.path.join(os.path.dirname(__file__), 'debian')) def test_dpkg_detect(): from rosdep2.platforms.debian import dpkg_detect m = Mock() m.return_value = '' val = dpkg_detect([], exec_fn=m) assert val == [], val val = dpkg_detect(['tinyxml-dev'], exec_fn=m) assert val == [], val #assert m.assert_called_with(['dpkg-query', '-W', '-f=\'${Package} ${Status}\n\'']) with open(os.path.join(get_test_dir(), 'dpkg-python-apt'), 'r') as f: m.return_value = f.read() val = dpkg_detect(['apt', 'tinyxml-dev', 'python'], exec_fn=m) assert val == ['apt', 'python'], val # test version lock code (should be filtered out w/o validation) val = dpkg_detect(['apt=1.8', 'tinyxml-dev', 'python=2.7'], exec_fn=m) assert val == ['apt=1.8', 'python=2.7'], val def test_AptInstaller(): from rosdep2.platforms.debian import AptInstaller @patch.object(AptInstaller, 'get_packages_to_install') def test(mock_method): installer = AptInstaller() mock_method.return_value = [] assert [] == installer.get_install_command(['fake']) mock_method.return_value = ['a', 'b'] expected = [['sudo', '-H', 'apt-get', 'install', '-y', 'a'], ['sudo', '-H', 'apt-get', 'install', '-y', 'b']] val = installer.get_install_command(['whatever'], interactive=False) print("VAL", val) assert val == expected, val expected = [['sudo', '-H', 'apt-get', 'install', 'a'], ['sudo', '-H', 'apt-get', 'install', 'b']] val = installer.get_install_command(['whatever'], interactive=True) assert val == expected, val try: test() except AssertionError: traceback.print_exc() raise ros-rosdep-0.11.4/test/test_rosdep_dependency_graph.py000066400000000000000000000173161260171354700231530ustar00rootroot00000000000000# 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 the 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. # Author William Woodall/wjwwood@gmail.com def test_DependencyGraph_Linear(): from rosdep2.dependency_graph import DependencyGraph # Normal A-B-C dg = DependencyGraph() dg['A']['installer_key'] = 'a_installer' dg['A']['install_keys'] = ['a'] dg['A']['dependencies'] = ['B'] dg['B']['installer_key'] = 'b_installer' dg['B']['install_keys'] = ['b'] dg['B']['dependencies'] = ['C'] dg['C']['installer_key'] = 'c_installer' dg['C']['install_keys'] = ['c'] dg['C']['dependencies'] = [] result = dg.get_ordered_dependency_list() expected = [('c_installer', ['c']), ('b_installer', ['b']), ('a_installer', ['a'])] assert result == expected, "Results did not match expectations: %s == %s"%(str(result),str(expected)) def test_DependencyGraph_Cycle(): from rosdep2.dependency_graph import DependencyGraph # Full Loop A-B-C-A-... dg = DependencyGraph() dg['A']['installer_key'] = 'a_installer' dg['A']['install_keys'] = ['a'] dg['A']['dependencies'] = ['B'] dg['B']['installer_key'] = 'b_installer' dg['B']['install_keys'] = ['b'] dg['B']['dependencies'] = ['C'] dg['C']['installer_key'] = 'c_installer' dg['C']['install_keys'] = ['c'] dg['C']['dependencies'] = ['A'] try: result = dg.get_ordered_dependency_list() assert False, "Doesn't fail, it should fail with an AssertionError because of the cycle." except AssertionError as e: if not str(e).startswith("A cycle in the dependency graph occurred with key"): assert False, "Throws AssertionError, but with the wrong message. Error was: %s: %s"%(type(e),str(e)) except Exception as e: assert False, "Throws and Exception, but not an AssertionError. Error was: %s: %s"%(type(e),str(e)) def test_DependencyGraph_Short_Cycle(): from rosdep2.dependency_graph import DependencyGraph # Short cycle A-B-C-D-B-C-D-... dg = DependencyGraph() dg['A']['installer_key'] = 'a_installer' dg['A']['install_keys'] = ['a'] dg['A']['dependencies'] = ['B'] dg['B']['installer_key'] = 'b_installer' dg['B']['install_keys'] = ['b'] dg['B']['dependencies'] = ['C'] dg['C']['installer_key'] = 'c_installer' dg['C']['install_keys'] = ['c'] dg['C']['dependencies'] = ['D'] dg['D']['installer_key'] = 'd_installer' dg['D']['install_keys'] = ['d'] dg['D']['dependencies'] = ['B'] try: result = dg.get_ordered_dependency_list() assert False, "Doesn't fail, it should fail with an AssertionError because of the cycle." except AssertionError as e: if not str(e).startswith("A cycle in the dependency graph occurred with key"): assert False, "Throws AssertionError, but with the wrong message. Error was: %s: %s"%(type(e),str(e)) except Exception as e: assert False, "Throws and Exception, but not an AssertionError. Error was: %s: %s"%(type(e),str(e)) def test_DependencyGraph_Invalid_Key(): from rosdep2.dependency_graph import DependencyGraph # Invalid graph A-B-C where C doesn't exist dg = DependencyGraph() dg['A']['installer_key'] = 'a_installer' dg['A']['install_keys'] = ['a'] dg['A']['dependencies'] = ['B'] dg['B']['installer_key'] = 'b_installer' dg['B']['install_keys'] = ['b'] dg['B']['dependencies'] = ['C'] try: result = dg.get_ordered_dependency_list() assert False, "Doesn't fail, it should fail with an KeyError because of the invalid rosdep key." except KeyError as e: if not str(e).endswith("does not exist in the dictionary of resolutions.'"): assert False, "Throws KeyError, but with the wrong message. Error was: %s: %s"%(type(e),str(e)) except Exception as e: assert False, "Throws and Exception, but not an KeyError. Error was: %s: %s"%(type(e),str(e)) def test_DependencyGraph_Invalid_Key2(): from rosdep2.dependency_graph import DependencyGraph # Invalid graph A-B-C where B doesn't exist dg = DependencyGraph() dg['A']['installer_key'] = 'a_installer' dg['A']['install_keys'] = ['a'] dg['A']['dependencies'] = ['B'] dg['C']['installer_key'] = 'c_installer' dg['C']['install_keys'] = ['c'] dg['C']['dependencies'] = [] try: result = dg.get_ordered_dependency_list() assert False, "Doesn't fail, it should fail with an KeyError because of the invalid rosdep key." except KeyError as e: if not str(e).endswith("does not exist in the dictionary of resolutions.'"): assert False, "Throws KeyError, but with the wrong message. Error was: %s: %s"%(type(e),str(e)) except Exception as e: assert False, "Throws and Exception, but not an KeyError. Error was: %s: %s"%(type(e),str(e)) def test_DependencyGraph_Multi_Root(): from rosdep2.dependency_graph import DependencyGraph # Multi root, shared dependency: A-B-C, D-C dg = DependencyGraph() dg['A']['installer_key'] = 'a_installer' dg['A']['install_keys'] = ['a'] dg['A']['dependencies'] = ['B'] dg['B']['installer_key'] = 'b_installer' dg['B']['install_keys'] = ['b'] dg['B']['dependencies'] = ['C'] dg['C']['installer_key'] = 'c_installer' dg['C']['install_keys'] = ['c'] dg['C']['dependencies'] = [] dg['D']['installer_key'] = 'd_installer' dg['D']['install_keys'] = ['d'] dg['D']['dependencies'] = ['C'] result = dg.get_ordered_dependency_list() # TODO: The expected might also have a different order, for example it might be: # [('c_installer', ['c']), ('d_installer', ['d']), ('b_installer', ['b']), ('a_installer', ['a'])] # But that wont invalidate the order from a dependency graph stand point expected = [ [('c_installer', ['c']), ('b_installer', ['b']), ('a_installer', ['a']), ('d_installer', ['d'])], [('c_installer', ['c']), ('d_installer', ['d']), ('b_installer', ['b']), ('a_installer', ['a'])], ] assert result in expected, "Results did not match expectations: %s == %s"%(str(result),str(expected)) def test_DependencyGraph_Realworld(): from rosdep2.dependency_graph import DependencyGraph # Real world example dg = DependencyGraph() dg['python-matplotlib']['installer_key'] = 'pip' dg['python-matplotlib']['install_keys'] = ['matplotlib'] dg['python-matplotlib']['dependencies'] = ['pkg-config'] dg['pkg-config']['installer_key'] = 'homebrew' dg['pkg-config']['install_keys'] = ['pkg-config'] dg['pkg-config']['dependencies'] = [] result = dg.get_ordered_dependency_list() expected = [('homebrew', ['pkg-config']), ('pip', ['matplotlib'])] assert result == expected, "Results did not match expectations: %s == %s"%(str(result),str(expected)) ros-rosdep-0.11.4/test/test_rosdep_gbpdistro_support.py000066400000000000000000000214331260171354700234400ustar00rootroot00000000000000# 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 the 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. import os try: from urllib.request import urlopen except ImportError: from urllib2 import urlopen def get_test_dir(): return os.path.abspath(os.path.join(os.path.dirname(__file__), 'sources.list.d')) def test_url_constants(): from rosdep2.gbpdistro_support import FUERTE_GBPDISTRO_URL for url_name, url in [ ('FUERTE_GBPDISTRO_URL', FUERTE_GBPDISTRO_URL)]: try: f = urlopen(url) f.read() f.close() except: assert False, "URL [%s][%s] failed to download" % (url_name, url) def test_get_gbprepo_as_rosdep_data(): from rosdep2.rosdistrohelper import get_index from rosdep2.gbpdistro_support import get_gbprepo_as_rosdep_data distro = list(get_index().distributions.keys())[0] data = get_gbprepo_as_rosdep_data(distro) for k in ['ros', 'catkin', 'genmsg']: assert k in data, data assert data['ros']['ubuntu'] try: get_gbprepo_as_rosdep_data('fooNonExistantDistro') assert False, "should have raised" except RuntimeError: pass def test_download_gbpdistro_as_rosdep_data(): from rosdep2.gbpdistro_support import download_gbpdistro_as_rosdep_data from rosdep2.gbpdistro_support import FUERTE_GBPDISTRO_URL from rosdep2.rep3 import REP3_TARGETS_URL from rosdep2 import DownloadFailure data = download_gbpdistro_as_rosdep_data(FUERTE_GBPDISTRO_URL) # don't go beyond this, this test is just making sure the download # plumbing is correct, not the loader. for k in ['ros', 'catkin', 'genmsg']: assert k in data, data assert data['ros']['ubuntu'] # try with bad url to trigger exception handling try: # override targets URL with bad URL download_gbpdistro_as_rosdep_data(FUERTE_GBPDISTRO_URL, targets_url='http://bad.ros.org/foo.yaml') assert False, "should have raised" except DownloadFailure: pass try: # use targets URL, which should have a bad format download_gbpdistro_as_rosdep_data(REP3_TARGETS_URL) assert False, "should have raised" except DownloadFailure: pass def test_gbprepo_to_rosdep_data_on_bad_inputs(): from rosdep2.gbpdistro_support import gbprepo_to_rosdep_data from rosdep2 import InvalidData simple_gbpdistro = {'release-name': 'foorte', 'repositories': {}, 'type': 'gbp'} targets = {'foorte': ['lucid', 'oneiric']} # test bad data try: gbprepo_to_rosdep_data(simple_gbpdistro, [targets]) assert False, "should have raised" except InvalidData: pass try: gbprepo_to_rosdep_data({ 'targets': 1, 'repositories': [], 'type': 'gbp'}, targets) assert False, "should have raised" except InvalidData: pass try: gbprepo_to_rosdep_data([], targets) assert False, "should have raised" except InvalidData: pass # release-name must be in targets try: gbprepo_to_rosdep_data({ 'release-name': 'barte', 'repositories': [], 'type': 'gbp'}, targets) assert False, "should have raised" except InvalidData: pass # gbp-distros must be list of dicts try: gbprepo_to_rosdep_data({ 'release-name': 'foorte', 'repositories': [1], 'type': 'gbp'}, targets) assert False, "should have raised" except InvalidData: pass # gbp-distro target must be 'all' or a list of strings try: bad_example = {'name': 'common', 'target': [1], 'url': 'git://github.com/wg-debs/common_msgs.git'} gbprepo_to_rosdep_data({ 'release-name': 'foorte', 'repositories': [bad_example], 'type': 'gbp'}, targets) assert False, "should have raised" except InvalidData: pass def test_gbprepo_to_rosdep_data_on_ok_input(): from rosdep2.gbpdistro_support import gbprepo_to_rosdep_data simple_gbpdistro = {'release-name': 'foorte', 'repositories': {}, 'type': 'gbp'} targets = {'foorte': ['lucid', 'oneiric']} # make sure our sample files work for the above checks before # proceeding to real data rosdep_data = gbprepo_to_rosdep_data(simple_gbpdistro, targets) assert rosdep_data is not None assert {} == rosdep_data gbpdistro_data = {'release-name': 'foorte', 'repositories': { 'common_msgs': dict( target='all', url='git://github.com/wg-debs/common_msgs.git', packages={ 'foo': 'subdir/foo', 'bar': 'subdir/bar' }), 'gazebo': dict( target=['lucid', 'natty'], url='git://github.com/wg-debs/gazebo.git'), 'foo-bar': dict( target=['precise'], url='git://github.com/wg-debs/gazebo.git', packages={ 'foo-bar': None }), }, 'type': 'gbp', } rosdep_data = gbprepo_to_rosdep_data(gbpdistro_data, targets) for k in ['foo', 'bar', 'gazebo', 'foo-bar']: assert k in rosdep_data, k # all targets and name transform # These are from the 'common_msgs' repo above. pkgs = ['foo', 'bar'] v = 'ros-foorte-%s' for pkg in pkgs: for p in ['lucid', 'oneiric']: rule = rosdep_data[pkg]['ubuntu'][p] assert rule['apt']['packages'] == [v % pkg], rule['apt']['packages'] for p in ['maverick', 'natty']: assert p not in rosdep_data[k]['ubuntu'] # target overrides pkg = 'gazebo' v = 'ros-foorte-gazebo' for p in ['lucid', 'natty']: rule = rosdep_data[pkg]['ubuntu'][p] assert rule['apt']['packages'] == [v], rule['apt']['packages'] for p in ['oneiric', 'precise']: assert p not in rosdep_data[pkg]['ubuntu'] # target overrides # These are from the 'foo-bar' repo above. v = 'ros-foorte-foo-bar' for pkg in ['foo-bar']: for p in ['precise']: rule = rosdep_data[pkg]['ubuntu'][p] assert rule['apt']['packages'] == [v], rule['apt']['packages'] for p in ['oneiric', 'natty', 'lucid']: assert p not in rosdep_data[pkg]['ubuntu'] def test_get_owner_name_homebrew(): from rosdep2.gbpdistro_support import get_owner_name empty_url = '' assert get_owner_name(empty_url) == 'ros', 'url: ' + empty_url https_test_url = 'https://github.com/' \ + 'ros/rosdistro/raw/master/releases/fuerte.yaml' assert get_owner_name(https_test_url) == 'ros', 'url: ' + https_test_url user_test_url = 'https://github.com/' \ + 'zklapow/rosdistro/raw/master/releases/fuerte.yaml' assert get_owner_name(user_test_url) == 'zklapow', 'url: ' + user_test_url non_github_url = 'https://ros.org/files/releases/fuerte.yaml' assert get_owner_name(non_github_url) == 'ros', 'url: ' + non_github_url ros-rosdep-0.11.4/test/test_rosdep_gem.py000066400000000000000000000101131260171354700204100ustar00rootroot00000000000000# Copyright (c) 2011, Willow Garage, Inc. # Copyright (c) 2012, Intermodalics, BVBA # 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 the 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. # Author Ken Conley/kwc@willowgarage.com # Author Ruben Smits/ruben.smits@intermodalics.eu import os import traceback from mock import Mock, patch def get_test_dir(): return os.path.abspath(os.path.join(os.path.dirname(__file__), 'gem')) def test_gem_detect(): from rosdep2.platforms.gem import gem_detect m = Mock() # test behavior with empty freeze m.return_value = '' val = gem_detect([], exec_fn=m) assert val == [], val val = gem_detect(['rdoc'], exec_fn=m) assert val == [], val # read list output into mock exec_fn with open(os.path.join(get_test_dir(), 'list_output'), 'r') as f: m.return_value = f.read() val = gem_detect(['rdoc'], exec_fn=m) assert val == ['rdoc'], val val = gem_detect(['rdoc', 'fakito', 'rake'], exec_fn=m) assert val == ['rake', 'rdoc'], val def test_GemInstaller_get_depends(): # make sure GemInstaller supports depends from rosdep2.platforms.gem import GemInstaller installer = GemInstaller() assert ['foo'] == installer.get_depends(dict(depends=['foo'])) def test_GemInstaller(): from rosdep2 import InstallFailed from rosdep2.platforms.gem import GemInstaller @patch('rosdep2.platforms.gem.is_gem_installed') def test_no_gem(mock_method): mock_method.return_value = False try: installer = GemInstaller() installer.get_install_command(['whatever']) assert False, "should have raised" except InstallFailed: pass test_no_gem() @patch('rosdep2.platforms.gem.is_gem_installed') @patch.object(GemInstaller, 'get_packages_to_install') def test(mock_method, mock_is_gem_installed): mock_is_gem_installed.return_value = True installer = GemInstaller() mock_method.return_value = [] assert [] == installer.get_install_command(['fake']) # no interactive option with GEM mock_method.return_value = ['a', 'b'] expected = [['sudo', '-H', 'gem', 'install', 'a'], ['sudo', '-H', 'gem', 'install', 'b']] val = installer.get_install_command(['whatever'], interactive=False) assert val == expected, val expected = [['sudo', '-H', 'gem', 'install', 'a'], ['sudo', '-H', 'gem', 'install', 'b']] val = installer.get_install_command(['whatever'], interactive=True) assert val == expected, val try: test() except AssertionError: traceback.print_exc() raise ros-rosdep-0.11.4/test/test_rosdep_gentoo.py000066400000000000000000000165111260171354700211430ustar00rootroot00000000000000# Copyright (c) 2011, 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 the 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. # Author Ken Conley/kwc@willowgarage.com, Murph Finnicum/murph@murph.cc import os import traceback from mock import Mock, patch import rospkg.os_detect def is_gentoo(): return rospkg.os_detect.Gentoo().is_os() def get_test_dir(): # not used yet return os.path.abspath(os.path.join(os.path.dirname(__file__), 'gentoo')) # Requires 2.7 @unittest.skipIf(not rospkg.os_detect.Gentoo().is_os(), "not running Gentoo") def test_portage_available(): if not is_gentoo(): print("Skipping not Gentoo") return from rosdep2.platforms.gentoo import portage_available original_exists = os.path.exists path_overrides = {} def mock_path(path): if path in path_overrides: return path_overrides[path] else: return original_exists(path) m = Mock(side_effect=mock_path) os.path.exists = m #Test with portageq missing m.reset_mock() path_overrides = {} path_overrides['/usr/bin/portageq'] = False path_overrides['/usr/bin/emerge'] = True val = portage_available() assert val==False, "Portage should not be available without portageq" #Test with emerge missing m.reset_mock() path_overrides = {} path_overrides['/usr/bin/portageq'] = True path_overrides['/usr/bin/emerge'] = False val = portage_available() assert val==False, "Portage should not be available without emerge" # Test with nothing missing m.reset_mock() path_overrides = {} path_overrides['/usr/bin/portageq'] = True path_overrides['/usr/bin/emerge'] = True val = portage_available() assert val==True, "Portage should be available" os.path.exists = original_exists # This actually tests portage_detect_single and portage_detect def test_portage_detect(): if not is_gentoo(): print("Skipping not Gentoo") return from rosdep2.platforms.gentoo import portage_detect m = Mock() m.return_value = [] val = portage_detect([], exec_fn=m) assert val == [], val # Test checking for a package that we do not have installed m = Mock(return_value = []) val = portage_detect(['tinyxml[stl]'], exec_fn=m) assert val == [], "Result was actually: %s" % val m.assert_called_with(['portageq', 'match', '/', 'tinyxml[stl]']) # Test checking for a package that we do have installed m = Mock(return_value = ['dev-libs/tinyxml-2.6.2-r1']) val = portage_detect(['tinyxml[stl]'], exec_fn=m) assert val == ['tinyxml[stl]'], "Result was actually: %s" % val m.assert_called_with(['portageq', 'match', '/', 'tinyxml[stl]']) # Test checking for two packages that we have installed m = Mock(side_effect = [['sys-devel/gcc-4.5.3-r2'], ['dev-libs/tinyxml-2.6.2-r1']]) val = portage_detect(['tinyxml[stl]', 'gcc'], exec_fn=m) assert val == ['gcc', 'tinyxml[stl]'], "Result was actually: %s" % val m.assert_any_call(['portageq', 'match', '/', 'tinyxml[stl]']) m.assert_any_call(['portageq', 'match', '/', 'gcc']) # Test checking for two missing packages m = Mock(side_effect = [[],[]]) val = portage_detect(['tinyxml[stl]', 'gcc'], exec_fn=m) assert val == [], "Result was actually: %s" % val m.assert_any_call(['portageq', 'match', '/', 'tinyxml[stl]']) m.assert_any_call(['portageq', 'match', '/', 'gcc']) # Test checking for one missing, one installed package m = Mock(side_effect = [['sys-devel/gcc-4.5.3-r2'], []]) val = portage_detect(['tinyxml[stl]', 'gcc'], exec_fn=m) assert val == ['gcc'], "Result was actually: %s" % val m.assert_any_call(['portageq', 'match', '/', 'tinyxml[stl]']) m.assert_any_call(['portageq', 'match', '/', 'gcc']) # Test checking for one installed, one missing package (reverse order) m = Mock(side_effect = [[], ['dev-libs/tinyxml-2.6.2-r1']]) val = portage_detect(['tinyxml[stl]', 'gcc'], exec_fn=m) assert val == ['tinyxml[stl]'], "Result was actually: %s" % val m.assert_any_call(['portageq', 'match', '/', 'tinyxml[stl]']) m.assert_any_call(['portageq', 'match', '/', 'gcc']) # Test duplicates (requesting the same package twice) #TODO what's the desired behavior here m = Mock(side_effect = [['dev-libs/tinyxml-2.6.2-r1'],['dev-libs/tinyxml-2.6.2-r1']]) val = portage_detect(['tinyxml[stl]', 'tinyxml[stl]'], exec_fn=m) assert val == ['tinyxml[stl]','tinyxml[stl]'], "Result was actually: %s" % val m.assert_any_call(['portageq', 'match', '/', 'tinyxml[stl]']) # and a second of the same, but any_call won't show that. # Test packages with multiple slot m = Mock(side_effect = [['dev-lang/python-2.7.2-r3','dev-lang/python-3.2.2']]) val = portage_detect(['python'], exec_fn=m) assert val == ['python'], "Result was actually: %s" % val m.assert_any_call(['portageq', 'match', '/', 'python']) def test_PortageInstaller(): if not is_gentoo(): print("Skipping not Gentoo") return from rosdep2.platforms.gentoo import PortageInstaller @patch.object(PortageInstaller, 'get_packages_to_install') def test(mock_method): installer = PortageInstaller() mock_method.return_value = [] assert [] == installer.get_install_command(['fake']) mock_method.return_value = ['a', 'b'] expected = [['sudo', '-H', 'emerge', 'a'], ['sudo', '-H', 'emerge', 'b']] val = installer.get_install_command(['whatever'], interactive=False) assert val == expected, val expected = [['sudo', '-H', 'emerge', '-a', 'a'], ['sudo', '-H', 'emerge', '-a', 'b']] val = installer.get_install_command(['whatever'], interactive=True) assert val == expected, val try: test() except AssertionError: traceback.print_exc() raise ros-rosdep-0.11.4/test/test_rosdep_installers.py000066400000000000000000000546151260171354700220370ustar00rootroot00000000000000# Copyright (c) 2011, 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 the 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. from __future__ import print_function import os import sys try: from cStringIO import StringIO except ImportError: from io import StringIO from rospkg import RosPack, RosStack def get_test_dir(): return os.path.abspath(os.path.dirname(__file__)) def get_cache_dir(): p = os.path.join(get_test_dir(), 'sources_cache') assert os.path.isdir(p) return p def create_test_SourcesListLoader(): from rosdep2.sources_list import SourcesListLoader return SourcesListLoader.create_default(sources_cache_dir=get_cache_dir(), verbose=True) def get_test_tree_dir(): return os.path.abspath(os.path.join(os.path.dirname(__file__), 'tree')) def get_test_rospkgs(): test_dir = get_test_tree_dir() ros_root = os.path.join(test_dir, 'ros') ros_package_path = os.path.join(test_dir, 'stacks') ros_paths = [ros_root, ros_package_path] rospack = RosPack(ros_paths=ros_paths) rosstack = RosStack(ros_paths=ros_paths) return rospack, rosstack def test_InstallerContext_ctor(): from rosdep2.installers import InstallerContext from rospkg.os_detect import OsDetect context = InstallerContext() assert context.get_os_detect() is not None assert isinstance(context.get_os_detect(), OsDetect) detect = OsDetect() context = InstallerContext(detect) assert context.get_os_detect() == detect assert len(context.get_installer_keys()) == 0 assert len(context.get_os_keys()) == 0 context.verbose = True assert context.get_os_detect() == detect assert len(context.get_installer_keys()) == 0 assert len(context.get_os_keys()) == 0 def test_InstallerContext_get_os_version_type(): from rospkg.os_detect import OS_UBUNTU, OsDetect from rosdep2.installers import InstallerContext context = InstallerContext() try: context.set_os_version_type(OS_UBUNTU, 'bad') assert False, "should check type" except ValueError: pass assert OsDetect.get_version == context.get_os_version_type(OS_UBUNTU) context.set_os_version_type(OS_UBUNTU, OsDetect.get_codename) assert OsDetect.get_codename == context.get_os_version_type(OS_UBUNTU) def test_InstallerContext_os_version_and_name(): from rospkg.os_detect import OsDetect from rosdep2.installers import InstallerContext context = InstallerContext() context.set_verbose(True) os_name, os_version = context.get_os_name_and_version() assert os_name is not None assert os_version is not None val = ("fakeos", "blah") context.set_os_override(*val) assert val == context.get_os_name_and_version() from mock import Mock from rospkg.os_detect import OsDetect os_detect_mock = Mock(spec=OsDetect) os_detect_mock.get_name.return_value = 'fakeos' os_detect_mock.get_version.return_value = 'fakeos-version' os_detect_mock.get_codename.return_value = 'fakeos-codename' context = InstallerContext(os_detect_mock) context.set_os_version_type('fakeos', os_detect_mock.get_codename) os_name, os_version = context.get_os_name_and_version() assert os_name == 'fakeos', os_name assert os_version == 'fakeos-codename', os_version context.set_os_version_type('fakeos', os_detect_mock.get_version) os_name, os_version = context.get_os_name_and_version() assert os_name == 'fakeos', os_name assert os_version == 'fakeos-version', os_version def test_InstallerContext_installers(): from rosdep2.installers import InstallerContext, Installer from rospkg.os_detect import OsDetect detect = OsDetect() context = InstallerContext(detect) context.verbose = True key = 'fake-apt' try: installer = context.get_installer(key) assert False, "should have raised: %s"%(installer) except KeyError: pass class Foo: pass class FakeInstaller(Installer): pass class FakeInstaller2(Installer): pass # test TypeError on set_installer try: context.set_installer(key, 1) assert False, "should have raised" except TypeError: pass try: context.set_installer(key, Foo()) assert False, "should have raised" except TypeError: pass try: # must be instantiated context.set_installer(key, FakeInstaller) assert False, "should have raised" except TypeError: pass installer = FakeInstaller() installer2 = FakeInstaller2() context.set_installer(key, installer) assert context.get_installer(key) == installer assert list(context.get_installer_keys()) == [key] # repeat with same args context.set_installer(key, installer) assert context.get_installer(key) == installer assert list(context.get_installer_keys()) == [key] # repeat with new installer context.set_installer(key, installer2) assert context.get_installer(key) == installer2 assert list(context.get_installer_keys()) == [key] # repeat with new key key2 = 'fake-port' context.set_installer(key2, installer2) assert context.get_installer(key2) == installer2 assert set(context.get_installer_keys()) == set([key, key2]) # test installer deletion key3 = 'fake3' context.set_installer(key3, installer2) assert context.get_installer(key3) == installer2 assert set(context.get_installer_keys()) == set([key, key2, key3]) context.set_installer(key3, None) try: context.get_installer(key3) assert False except KeyError: pass assert set(context.get_installer_keys()) == set([key, key2]) def test_InstallerContext_os_installers(): from rosdep2.installers import InstallerContext, Installer from rospkg.os_detect import OsDetect detect = OsDetect() context = InstallerContext(detect) context.verbose = True os_key = 'ubuntu' try: context.get_os_installer_keys(os_key) assert False, "should have raised" except KeyError: pass try: context.get_default_os_installer_key(os_key) assert False, "should have raised" except KeyError: pass try: context.add_os_installer_key(os_key, 'fake-key') assert False, "should have raised" except KeyError: pass try: context.set_default_os_installer_key(os_key, 'non-method') assert False, "should have raised" except KeyError: pass try: context.set_default_os_installer_key(os_key, lambda self: 'fake-key') assert False, "should have raised" except KeyError: pass try: context.get_default_os_installer_key('bad-os') assert False, "should have raised" except KeyError: pass installer_key1 = 'fake1' installer_key2 = 'fake2' class FakeInstaller(Installer): pass class FakeInstaller2(Installer): pass # configure our context with two valid installers context.set_installer(installer_key1, FakeInstaller()) context.set_installer(installer_key2, FakeInstaller2()) # start adding installers for os_key context.add_os_installer_key(os_key, installer_key1) assert context.get_os_installer_keys(os_key) == [installer_key1] # retest set_default_os_installer_key, now with installer_key not configured on os try: context.set_default_os_installer_key(os_key, lambda self: installer_key2) assert False, "should have raised" except KeyError as e: assert 'add_os_installer' in str(e), e # now properly add in key2 context.add_os_installer_key(os_key, installer_key2) assert set(context.get_os_installer_keys(os_key)) == set([installer_key1, installer_key2]) # test default assert None == context.get_default_os_installer_key(os_key) context.set_default_os_installer_key(os_key, lambda self: installer_key1) assert installer_key1 == context.get_default_os_installer_key(os_key) context.set_default_os_installer_key(os_key, lambda self: installer_key2) assert installer_key2 == context.get_default_os_installer_key(os_key) # retest set_default_os_installer_key, now with invalid os try: context.set_default_os_installer_key('bad-os', lambda self: installer_key1) assert False, "should have raised" except KeyError: pass def test_Installer_tripwire(): from rosdep2.installers import Installer try: Installer().is_installed('foo') assert False except NotImplementedError: pass try: Installer().get_install_command('foo') assert False except NotImplementedError: pass try: Installer().resolve({}) assert False except NotImplementedError: pass try: Installer().unique([]) assert False except NotImplementedError: pass assert Installer().get_depends({}) == [] def detect_fn_empty(packages): return [] def detect_fn_all(packages): return packages # return any packages that are string length 1 def detect_fn_single(packages): return [p for p in packages if len(p) == 1] def test_PackageManagerInstaller(): from rosdep2.installers import PackageManagerInstaller try: PackageManagerInstaller(detect_fn_all).get_install_command(['foo']) assert False except NotImplementedError: pass def test_PackageManagerInstaller_resolve(): from rosdep2 import InvalidData from rosdep2.installers import PackageManagerInstaller installer = PackageManagerInstaller(detect_fn_all) assert ['baz'] == installer.resolve(dict(depends=['foo', 'bar'], packages=['baz'])) assert ['baz', 'bar'] == installer.resolve(dict(packages=['baz', 'bar'])) #test string logic assert ['baz'] == installer.resolve(dict(depends=['foo', 'bar'], packages='baz')) assert ['baz', 'bar'] == installer.resolve(dict(packages='baz bar')) assert ['baz'] == installer.resolve('baz') assert ['baz', 'bar'] == installer.resolve('baz bar') #test list logic assert ['baz'] == installer.resolve(['baz']) assert ['baz', 'bar'] == installer.resolve(['baz', 'bar']) # test invalid data try: installer.resolve(0) assert False, "should have raised" except InvalidData: pass def test_PackageManagerInstaller_depends(): from rosdep2.installers import PackageManagerInstaller installer = PackageManagerInstaller(detect_fn_all, supports_depends=True) assert ['foo', 'bar'] == installer.get_depends(dict(depends=['foo', 'bar'], packages=['baz'])) installer = PackageManagerInstaller(detect_fn_all, supports_depends=False) assert [] == installer.get_depends(dict(depends=['foo', 'bar'], packages=['baz'])) def test_PackageManagerInstaller_unique(): from rosdep2.installers import PackageManagerInstaller installer = PackageManagerInstaller(detect_fn_all) assert [] == installer.unique() assert [] == installer.unique([]) assert [] == installer.unique([], []) assert ['a'] == installer.unique([], [], ['a']) assert ['a'] == installer.unique(['a'], [], ['a']) assert set(['a', 'b', 'c']) == set(installer.unique(['a', 'b', 'c'], ['a', 'b', 'c'])) assert set(['a', 'b', 'c']) == set(installer.unique(['a'], ['b'], ['c'])) assert set(['a', 'b', 'c']) == set(installer.unique(['a', 'b'], ['c'])) assert set(['a', 'b', 'c']) == set(installer.unique(['a', 'b'], ['c', 'a'])) def test_PackageManagerInstaller_is_installed(): from rosdep2.installers import PackageManagerInstaller installer = PackageManagerInstaller(detect_fn_all) for r in ['a', 'b', 'c']: assert True == installer.is_installed(r), installer.is_installed(r) installer = PackageManagerInstaller(detect_fn_empty) for r in ['a', 'b', 'c']: assert False == installer.is_installed(r), installer.is_installed(r) def test_PackageManagerInstaller_get_packages_to_install(): from rosdep2.installers import PackageManagerInstaller installer = PackageManagerInstaller(detect_fn_all) assert [] == installer.get_packages_to_install([]) assert [] == installer.get_packages_to_install(['a', 'b', 'c']) assert set(['a', 'b', 'c']) == set(installer.get_packages_to_install(['a', 'b', 'c'], reinstall=True)) installer = PackageManagerInstaller(detect_fn_empty) assert set(['a', 'b', 'c']) == set(installer.get_packages_to_install(['a', 'b', 'c'])) assert set(['a', 'b', 'c']) == set(installer.get_packages_to_install(['a', 'b', 'c'], reinstall=True)) installer = PackageManagerInstaller(detect_fn_single) assert set(['baba', 'cada']) == set(installer.get_packages_to_install(['a', 'baba', 'b', 'cada', 'c'])) def test_RosdepInstaller_ctor(): # tripwire/coverage from rosdep2 import create_default_installer_context from rosdep2.lookup import RosdepLookup from rosdep2.installers import RosdepInstaller lookup = RosdepLookup.create_from_rospkg() context = create_default_installer_context() installer = RosdepInstaller(context, lookup) assert lookup == installer.lookup assert context == installer.installer_context def test_RosdepInstaller_get_uninstalled(): from rosdep2 import create_default_installer_context from rosdep2.lookup import RosdepLookup from rosdep2.installers import RosdepInstaller from rosdep2.platforms.debian import APT_INSTALLER from rosdep2.lookup import RosdepLookup rospack, rosstack = get_test_rospkgs() # create our test fixture. use most of the default toolchain, but # replace the apt installer with one that we can have more fun # with. we will do all tests with ubuntu lucid keys -- other # tests should cover different resolution cases. sources_loader = create_test_SourcesListLoader() lookup = RosdepLookup.create_from_rospkg(rospack=rospack, rosstack=rosstack, sources_loader=sources_loader) context = create_default_installer_context() context.set_os_override('ubuntu', 'lucid') installer = RosdepInstaller(context, lookup) # in this first test, detect_fn detects everything as installed fake_apt = get_fake_apt(lambda x: x) context.set_installer(APT_INSTALLER, fake_apt) for verbose in [True, False]: tests = [['roscpp_fake'], ['roscpp_fake', 'rospack_fake'], ['empty_package'], ['roscpp_fake', 'rospack_fake', 'empty_package'], ['roscpp_fake', 'rospack_fake'], ] for test in tests: uninstalled, errors = installer.get_uninstalled(test, verbose) assert not uninstalled, uninstalled assert not errors, errors # in this second test, detect_fn detects nothing as installed fake_apt = get_fake_apt(lambda x: []) context.set_installer(APT_INSTALLER, fake_apt) for verbose in [True, False]: uninstalled, errors = installer.get_uninstalled(['empty'], verbose) assert not uninstalled, uninstalled assert not errors expected = set(['libltdl-dev', 'libboost1.40-all-dev', 'libtool']) uninstalled, errors = installer.get_uninstalled(['roscpp_fake'], verbose) keys, values = zip(*uninstalled) apt_uninstalled = [] for k, v in uninstalled: if k == APT_INSTALLER: apt_uninstalled.extend(v) assert list(set(keys)) == [APT_INSTALLER] assert set(apt_uninstalled) == expected assert not errors expected = ['libtinyxml-dev'] uninstalled, errors = installer.get_uninstalled(['rospack_fake'], verbose) keys, values = zip(*uninstalled) apt_uninstalled = [] for k, v in uninstalled: if k == APT_INSTALLER: apt_uninstalled.extend(v) assert list(set(keys)) == [APT_INSTALLER] assert apt_uninstalled == expected, uninstalled assert not errors def get_fake_apt(detect_fn): # mainly did this to keep coverage results from rosdep2.installers import PackageManagerInstaller class FakeAptInstaller(PackageManagerInstaller): """ An implementation of the Installer for use on debian style systems. """ def __init__(self): super(FakeAptInstaller, self).__init__(detect_fn) def get_install_command(self, resolved, interactive=True, reinstall=False): return [[resolved, interactive, reinstall]] return FakeAptInstaller() def test_RosdepInstaller_get_uninstalled_unconfigured(): from rosdep2 import create_default_installer_context, RosdepInternalError from rosdep2.lookup import RosdepLookup, ResolutionError from rosdep2.installers import RosdepInstaller, PackageManagerInstaller from rosdep2.platforms.debian import APT_INSTALLER from rosdep2.lookup import RosdepLookup rospack, rosstack = get_test_rospkgs() sources_loader = create_test_SourcesListLoader() # create our test fixture. we want to setup a fixture that cannot resolve the rosdep data in order to test error conditions lookup = RosdepLookup.create_from_rospkg(rospack=rospack, rosstack=rosstack, sources_loader=sources_loader) context = create_default_installer_context() context.set_os_override('ubuntu', 'lucid') installer = RosdepInstaller(context, lookup) # - delete the apt installer context.set_installer(APT_INSTALLER, None) for verbose in [True, False]: uninstalled, errors = installer.get_uninstalled(['empty'], verbose) assert not uninstalled, uninstalled assert not errors # make sure there is an error when we lookup something that resolves to an apt depend uninstalled, errors = installer.get_uninstalled(['roscpp_fake'], verbose) assert not uninstalled, uninstalled assert list(errors.keys()) == ['roscpp_fake'] uninstalled, errors = installer.get_uninstalled(['roscpp_fake', 'stack1_p1'], verbose) assert not uninstalled, uninstalled assert set(errors.keys()) == set(['roscpp_fake', 'stack1_p1']) print(errors) assert isinstance(errors['roscpp_fake'], ResolutionError), errors['roscpp_fake'][0] # fake/bad installer to test that we re-cast general installer issues class BadInstaller(PackageManagerInstaller): def __init__(self): super(BadInstaller, self).__init__(lambda x: x) def get_packages_to_install(*args): raise Exception("deadbeef") context.set_installer(APT_INSTALLER, BadInstaller()) try: installer.get_uninstalled(['roscpp_fake']) assert False, "should have raised" except RosdepInternalError as e: assert 'apt' in str(e) # annoying mock to test generally impossible error condition from mock import Mock lookup = Mock(spec=RosdepLookup) lookup.resolve_all.return_value = ([('bad-key', ['stuff'])], []) installer = RosdepInstaller(context, lookup) try: installer.get_uninstalled(['roscpp_fake']) assert False, "should have raised" except RosdepInternalError: pass from contextlib import contextmanager @contextmanager def fakeout(): realstdout = sys.stdout realstderr = sys.stderr fakestdout = StringIO() fakestderr = StringIO() sys.stdout = fakestdout sys.stderr = fakestderr yield fakestdout, fakestderr sys.stdout = realstdout sys.stderr = realstderr def test_RosdepInstaller_install_resolved(): from rosdep2 import create_default_installer_context from rosdep2.lookup import RosdepLookup from rosdep2.installers import RosdepInstaller from rosdep2.platforms.debian import APT_INSTALLER from rosdep2.lookup import RosdepLookup rospack, rosstack = get_test_rospkgs() # create our test fixture. use most of the default toolchain, but # replace the apt installer with one that we can have more fun # with. we will do all tests with ubuntu lucid keys -- other # tests should cover different resolution cases. sources_loader = create_test_SourcesListLoader() lookup = RosdepLookup.create_from_rospkg(rospack=rospack, rosstack=rosstack, sources_loader=sources_loader) context = create_default_installer_context() context.set_os_override('ubuntu', 'lucid') installer = RosdepInstaller(context, lookup) with fakeout() as (stdout, stderr): installer.install_resolved(APT_INSTALLER, [], simulate=True, verbose=False) with fakeout() as (stdout, stderr): installer.install_resolved(APT_INSTALLER, [], simulate=True, verbose=True) assert stdout.getvalue().strip() == '#No packages to install' with fakeout() as (stdout, stderr): try: installer.install_resolved(APT_INSTALLER, ['rosdep-fake1', 'rosdep-fake2'], simulate=True, verbose=True) except OSError as e: if str(e).count('[Errno 2] No such file or directory') == 0: raise return True stdout_lines = [x.strip() for x in stdout.getvalue().split('\n') if x.strip()] assert len(stdout_lines) == 3 assert stdout_lines[0] == '#[apt] Installation commands:' assert 'sudo -H apt-get install rosdep-fake1' in stdout_lines, 'stdout_lines: %s' % stdout_lines assert 'sudo -H apt-get install rosdep-fake2' in stdout_lines, 'stdout_lines: %s' % stdout_lines ros-rosdep-0.11.4/test/test_rosdep_issue30.py000066400000000000000000000044051260171354700211420ustar00rootroot00000000000000import os import subprocess as sp import tempfile import unittest from rosdep2 import main as rdmain class Issue30TestCase(unittest.TestCase): def testIssue30(self): return True d = make_temp_dir() try: cd(d) script = '''#!/bin/bash mkdir ws mkdir ws/src mkdir ws/build cd ws/src catkin_init_workspace > /dev/null cd .. cd build cmake ../src > /dev/null cd ../src git clone -b groovy-devel git://github.com/ros-drivers/joystick_drivers.git > /dev/null ''' run_script('commands.bash', script) source('ws/build/devel/setup.sh') lookup = make_lookup() keys = rdmain.get_keys(lookup, ['spacenav_node'], recursive=True) expected = ''' geometry_msgs libspnav-dev libx11-dev roscpp sensor_msgs spacenavd '''.split() self.assertEqual(expected, sorted(keys)) finally: sp.call(['rm', '-rf', d]) def make_temp_dir(): return tempfile.mkdtemp() def cd(d): os.chdir(d) def write_file(filename, contents): with open(filename, 'w') as f: f.write(contents) def run_script(filename, contents): """ Creates a script with the given filename and contents, runs it and returns the output. """ write_file(filename, contents) os.chmod(filename, 0x755) p = sp.Popen([os.path.join('.', filename)], stdout=sp.PIPE) p.wait() return p.stdout.read() # http://pythonwise.blogspot.com/2010/04/sourcing-shell-script.html def source(script): """ Sources a shell script at a given path, updating the environment. """ pipe = sp.Popen(". %s; env" % script, stdout=sp.PIPE, shell=True) data = pipe.communicate()[0] env = dict((line.split("=", 1) for line in data.splitlines())) os.environ.update(env) def make_lookup(): """ Creates a RosdepLookup object. """ import rosdep2.sources_list as sl import rosdep2.lookup as rdl sources_loader = sl.SourcesListLoader.create_default( sources_cache_dir=sl.get_sources_cache_dir(), verbose=True) return rdl.RosdepLookup.create_from_rospkg(sources_loader=sources_loader) if __name__ == '__main__': unittest.main() ros-rosdep-0.11.4/test/test_rosdep_loader.py000066400000000000000000000046371260171354700211240ustar00rootroot00000000000000# Copyright (c) 2011, 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 the 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. from mock import Mock def test_RosdepLoader(): #tripwire tests from rosdep2.loader import RosdepLoader loader = RosdepLoader() try: loader.load_view('foo', Mock()) assert False, "should have raised NotImplemented" except NotImplementedError: pass try: loader.get_loadable_resources() assert False, "should have raised NotImplementedError" except NotImplementedError: pass try: loader.get_loadable_views() assert False, "should have raised NotImplementedError" except NotImplementedError: pass try: loader.get_view_key('foo') assert False, "should have raised NotImplementedError" except NotImplementedError: pass try: loader.get_rosdeps('foo', implicit=False) assert False, "should have raised NotImplementedError" except NotImplementedError: pass ros-rosdep-0.11.4/test/test_rosdep_lookup.py000066400000000000000000000473401260171354700211650ustar00rootroot00000000000000# Copyright (c) 2011, 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 the 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. from __future__ import print_function import os import yaml from rospkg import RosPack, RosStack, ResourceNotFound BASE_URL = 'https://github.com/ros/rosdistro/raw/master/rosdep/base.yaml' PYTHON_URL = 'https://github.com/ros/rosdistro/raw/master/rosdep/python.yaml' def get_test_dir(): return os.path.abspath(os.path.dirname(__file__)) def get_test_tree_dir(): return os.path.abspath(os.path.join(os.path.dirname(__file__), 'tree')) def get_cache_dir(): p = os.path.join(get_test_dir(), 'sources_cache') assert os.path.isdir(p) return p def create_test_SourcesListLoader(): from rosdep2.sources_list import SourcesListLoader return SourcesListLoader.create_default(sources_cache_dir=get_cache_dir(), verbose=True) def get_cache_raw(): cache_rosdep_path = os.path.join(get_cache_dir(), '0a12d6e7b0d47be9b76e7726720e4cb79528cbaa') with open(cache_rosdep_path) as f: cache_raw = yaml.load(f.read()) return cache_raw def get_cache_raw_python(): cache_rosdep_path = os.path.join(get_cache_dir(), 'f6f4ef95664e373cd4754501337fa217f5b55d91') with open(cache_rosdep_path) as f: cache_raw = yaml.load(f.read()) return cache_raw def get_test_rospkgs(): test_dir = get_test_tree_dir() ros_root = os.path.join(test_dir, 'ros') ros_package_path = os.path.join(test_dir, 'stacks') ros_paths = [ros_root, ros_package_path] rospack = RosPack(ros_paths=ros_paths) rosstack = RosStack(ros_paths=ros_paths) return rospack, rosstack FAKE_TINYXML_RULE = """testtinyxml: ubuntu: lucid: apt: packages: libtinyxml-dev debian: libtinyxml-dev osx: source: uri: 'http://kforge.ros.org/rosrelease/viewvc/sourcedeps/tinyxml/tinyxml-2.6.2-1.rdmanifest' md5sum: 13760e61e08c9004493c302a16966c42 fedora: yum: packages: tinyxml-devel""" def test_RosdepDefinition(): from rosdep2.lookup import RosdepDefinition, ResolutionError, InvalidData d = dict(a=1, b=2, c=3) def1 = RosdepDefinition('d', d) assert def1.rosdep_key == 'd' assert def1.data == d def2 = RosdepDefinition('d', d, 'file1.txt') assert def2.rosdep_key == 'd' assert def2.data == d assert def2.origin == 'file1.txt' # test get_rule_for_platform # - test w/invalid data try: RosdepDefinition('dbad', 'foo', 'bad.txt').get_rule_for_platform('ubuntu', 'hardy', ['apt'], 'apt') assert False, "should have failed" except InvalidData: pass try: RosdepDefinition('dbad', {'ubuntu': 1}, 'bad2.txt').get_rule_for_platform('ubuntu', 'hardy', ['apt'], 'apt') assert False, "should have failed" except InvalidData: pass try: RosdepDefinition('dbad', {'ubuntu': {'hardy': 1}}, 'bad2.txt').get_rule_for_platform('ubuntu', 'hardy', ['apt'], 'apt') assert False, "should have failed" except InvalidData: pass # - test w/valid data d2 = yaml.load(FAKE_TINYXML_RULE)['testtinyxml'] definition = RosdepDefinition('d2', d2, 'file2.txt') # - tripwire str(definition) val = definition.get_rule_for_platform('fedora', 'fake-version', ['yum', 'source', 'pip'], 'yum') assert val == ('yum', dict(packages='tinyxml-devel')), val val = definition.get_rule_for_platform('debian', 'sid', ['apt', 'source', 'pip'], 'apt') assert val == ('apt', 'libtinyxml-dev') val = definition.get_rule_for_platform('ubuntu', 'lucid', ['apt', 'source', 'pip'], 'apt') assert val == ('apt', dict(packages='libtinyxml-dev')), val val = definition.get_rule_for_platform('osx', 'snow', ['macports', 'source', 'pip'], 'macports') assert val == ('source', dict(md5sum='13760e61e08c9004493c302a16966c42', uri='http://kforge.ros.org/rosrelease/viewvc/sourcedeps/tinyxml/tinyxml-2.6.2-1.rdmanifest')), val # test bad resolutions try: val = definition.get_rule_for_platform('ubuntu', 'hardy', ['apt', 'source', 'pip'], 'apt') assert False, "should have raised: %s"%(str(val)) except ResolutionError as e: assert e.rosdep_key == 'd2' assert e.rosdep_data == d2 assert e.os_name == 'ubuntu' assert e.os_version == 'hardy' # tripwire str(e) try: val = definition.get_rule_for_platform('fakeos', 'fakeversion', ['apt', 'source', 'pip'], 'apt') assert False, "should have raised: %s"%(str(val)) except ResolutionError as e: assert e.rosdep_key == 'd2' assert e.rosdep_data == d2 assert e.os_name == 'fakeos' assert e.os_version == 'fakeversion' # tripwire str(e) # test reverse merging OS things (first is default) definition = RosdepDefinition('test', {'debian': 'libtest-dev'}, 'fake-1.txt') # rule should work as expected before reverse-merge val = definition.get_rule_for_platform('debian', 'sid', ['apt', 'source', 'pip'], 'apt') assert val == ('apt', 'libtest-dev'), val try: val = definition.get_rule_for_platform('ubuntu', 'precise', ['apt', 'source', 'pip'], 'apt') assert False, "should have failed" except ResolutionError as e: assert e.rosdep_key == 'test' assert e.os_name == 'ubuntu' assert e.os_version == 'precise' # tripwire? str(e) definition.reverse_merge({'ubuntu': {'precise': {'apt': 'ros-fuerte-test'}}}, 'fake-gbp.yaml') val = definition.get_rule_for_platform('ubuntu', 'precise', ['apt', 'source', 'pip'], 'apt') assert val == ('apt', 'ros-fuerte-test'), val val = definition.get_rule_for_platform('debian', 'sid', ['apt', 'source', 'pip'], 'apt') assert val == ('apt', 'libtest-dev'), val def test_RosdepView_merge(): from rosdep2.model import RosdepDatabaseEntry from rosdep2.lookup import RosdepView # rosdep data must be dictionary of dictionaries data = dict(a=dict(x=1), b=dict(y=2), c=dict(z=3)) # create empty view and test view = RosdepView('common') assert len(view.keys()) == 0 # - tripwire str(view) # make sure lookups fail if not found try: view.lookup('notfound') assert False, "should have raised KeyError" except KeyError as e: assert 'notfound' in str(e) # merge into empty view d = RosdepDatabaseEntry(data, [], 'origin') view.merge(d) assert set(view.keys()) == set(data.keys()) for k, v in data.items(): assert view.lookup(k).data == v, "%s vs. %s"%(view.lookup(k), v) # merge exact same data d2 = RosdepDatabaseEntry(data, [], 'origin2') view.merge(d2) assert set(view.keys()) == set(data.keys()) for k, v in data.items(): assert view.lookup(k).data == v # merge new for 'd', 'e' d3 = RosdepDatabaseEntry(dict(d=dict(o=4), e=dict(p=5)), [], 'origin3') view.merge(d3) assert set(view.keys()) == set(list(data.keys()) + ['d', 'e']) for k, v in data.items(): assert view.lookup(k).data == v assert view.lookup('d').data == dict(o=4) assert view.lookup('e').data == dict(p=5) # merge different data for 'a' d4 = RosdepDatabaseEntry(dict(a=dict(x=2)), [], 'origin4') # - first w/o override, should not bump view.merge(d4, override=False) assert view.lookup('a').data == dict(x=1), view.lookup('a').data assert view.lookup('b').data == dict(y=2) assert view.lookup('c').data == dict(z=3) assert view.lookup('d').data == dict(o=4) assert view.lookup('e').data == dict(p=5) # - now w/ override view.merge(d4, override=True) assert view.lookup('a').data == dict(x=2) assert view.lookup('b').data == dict(y=2) assert view.lookup('c').data == dict(z=3) assert view.lookup('d').data == dict(o=4) assert view.lookup('e').data == dict(p=5) # - tripwire str(view) def test_RosdepLookup_get_rosdeps(): from rosdep2.loader import RosdepLoader from rosdep2.lookup import RosdepLookup rospack, rosstack = get_test_rospkgs() sources_loader = create_test_SourcesListLoader() lookup = RosdepLookup.create_from_rospkg(rospack=rospack, rosstack=rospack, sources_loader=sources_loader) assert lookup.get_loader() is not None assert isinstance(lookup.get_loader(), RosdepLoader) print(lookup.get_rosdeps('empty_package')) assert lookup.get_rosdeps('empty_package') == [] try: assert lookup.get_rosdeps('not a resource') == [] assert False, "should have raised" except ResourceNotFound: pass print(lookup.get_rosdeps('stack1_p1')) assert set(lookup.get_rosdeps('stack1_p1')) == set(['stack1_dep1', 'stack1_p1_dep1', 'stack1_p1_dep2']) assert set(lookup.get_rosdeps('stack1_p1', implicit=False)) == set(['stack1_dep1', 'stack1_p1_dep1', 'stack1_p1_dep2']) print(lookup.get_rosdeps('stack1_p2')) assert set(lookup.get_rosdeps('stack1_p2', implicit=False)) == set(['stack1_dep1', 'stack1_dep2', 'stack1_p2_dep1']), set(lookup.get_rosdeps('stack1_p2')) assert set(lookup.get_rosdeps('stack1_p2', implicit=True)) == set(['stack1_dep1', 'stack1_dep2', 'stack1_p1_dep1', 'stack1_p1_dep2', 'stack1_p2_dep1']), set(lookup.get_rosdeps('stack1_p2')) def test_RosdepLookup_get_resources_that_need(): from rosdep2.lookup import RosdepLookup rospack, rosstack = get_test_rospkgs() sources_loader = create_test_SourcesListLoader() lookup = RosdepLookup.create_from_rospkg(rospack=rospack, rosstack=rospack, sources_loader=sources_loader) assert lookup.get_resources_that_need('fake') == [] assert set(lookup.get_resources_that_need('stack1_dep1')) == set(['stack1_p1', 'stack1_p2']) assert lookup.get_resources_that_need('stack1_dep2') == ['stack1_p2'] assert lookup.get_resources_that_need('stack1_p1_dep1') == ['stack1_p1'] def test_RosdepLookup_create_from_rospkg(): from rosdep2.lookup import RosdepLookup rospack, rosstack = get_test_rospkgs() # these are just tripwire, can't actually test as it depends on external env lookup = RosdepLookup.create_from_rospkg() lookup = RosdepLookup.create_from_rospkg(rospack=rospack) assert rospack == lookup.loader._rospack lookup = RosdepLookup.create_from_rospkg(rospack=rospack, rosstack=rosstack) assert rospack == lookup.loader._rospack assert rosstack == lookup.loader._rosstack def test_RosdepLookup_get_rosdep_view_for_resource(): from rosdep2.lookup import RosdepLookup from rosdep2.rospkg_loader import DEFAULT_VIEW_KEY, RosPkgLoader rospack, rosstack = get_test_rospkgs() sources_loader = create_test_SourcesListLoader() lookup = RosdepLookup.create_from_rospkg(rospack=rospack, rosstack=rosstack, sources_loader=sources_loader) # assumption of our tests assert isinstance(lookup.loader, RosPkgLoader) # depends on nothing cache_raw = get_cache_raw() py_cache_raw = get_cache_raw_python() # - first pass: no cache ros_view = lookup.get_rosdep_view_for_resource('roscpp_fake') libtool = ros_view.lookup('testlibtool') assert BASE_URL == libtool.origin assert cache_raw['testlibtool'] == libtool.data python = ros_view.lookup('testpython') assert PYTHON_URL == python.origin assert py_cache_raw['testpython'] == python.data # package not in stack, should return assert lookup.get_rosdep_view_for_resource('just_a_package').name is DEFAULT_VIEW_KEY def test_RosdepLookup_get_rosdep_view(): from rosdep2.lookup import RosdepLookup rospack, rosstack = get_test_rospkgs() sources_loader = create_test_SourcesListLoader() lookup = RosdepLookup.create_from_rospkg(rospack=rospack, rosstack=rosstack, sources_loader=sources_loader) # depends on nothing cache_raw = get_cache_raw() py_cache_raw = get_cache_raw_python() # - first pass: no cache ros_view = lookup.get_rosdep_view('ros') libtool = ros_view.lookup('testlibtool') assert BASE_URL == libtool.origin assert cache_raw['testlibtool'] == libtool.data python = ros_view.lookup('testpython') assert PYTHON_URL == python.origin assert py_cache_raw['testpython'] == python.data, python.data # - second pass: with cache ros_view = lookup.get_rosdep_view('ros') libtool = ros_view.lookup('testlibtool') assert BASE_URL == libtool.origin assert cache_raw['testlibtool'] == libtool.data # depends on ros stack1_view = lookup.get_rosdep_view('stack1') stack1_rosdep_path = os.path.join(rosstack.get_path('stack1'), 'rosdep.yaml') # - make sure ros data is available libtool = stack1_view.lookup('testlibtool') assert BASE_URL == libtool.origin assert cache_raw['testlibtool'] == libtool.data python = stack1_view.lookup('testpython') assert PYTHON_URL == python.origin assert py_cache_raw['testpython'] == python.data def test_RosdepLookup_get_errors(): from rosdep2.lookup import RosdepLookup rospack, rosstack = get_test_rospkgs() tree_dir = get_test_tree_dir() sources_loader = create_test_SourcesListLoader() lookup = RosdepLookup.create_from_rospkg(rospack=rospack, rosstack=rosstack, sources_loader=sources_loader) # shouldn't be any errors (yet) assert lookup.get_errors() == [] # force errors lookup._load_all_views(lookup.loader) #TODO: force errors. Previous tests relied on bad stack views. #Now we need a bad sources cache. def test_RosdepLookup_get_views_that_define(): from rosdep2.lookup import RosdepLookup rospack, rosstack = get_test_rospkgs() tree_dir = get_test_tree_dir() sources_loader = create_test_SourcesListLoader() lookup = RosdepLookup.create_from_rospkg(rospack=rospack, rosstack=rosstack, sources_loader=sources_loader) val = lookup.get_views_that_define('testboost') assert len(val) == 1 entry = val[0] assert entry == (BASE_URL, BASE_URL), entry val = lookup.get_views_that_define('testpython') assert len(val) == 1 entry = val[0] assert entry == (PYTHON_URL, PYTHON_URL), entry def test_RosdepLookup_resolve_all_errors(): from rosdep2.installers import InstallerContext from rosdep2.lookup import RosdepLookup, ResolutionError rospack, rosstack = get_test_rospkgs() sources_loader = create_test_SourcesListLoader() lookup = RosdepLookup.create_from_rospkg(rospack=rospack, rosstack=rosstack, sources_loader=sources_loader) # the installer context has nothing in it, lookups will fail installer_context = InstallerContext() installer_context.set_os_override('ubuntu', 'lucid') resolutions, errors = lookup.resolve_all(['rospack_fake'], installer_context) assert 'rospack_fake' in errors resolutions, errors = lookup.resolve_all(['not_a_resource'], installer_context) assert 'not_a_resource' in errors, errors def test_RosdepLookup_resolve_errors(): from rosdep2.installers import InstallerContext from rosdep2.lookup import RosdepLookup, ResolutionError rospack, rosstack = get_test_rospkgs() sources_loader = create_test_SourcesListLoader() lookup = RosdepLookup.create_from_rospkg(rospack=rospack, rosstack=rosstack, sources_loader=sources_loader) # the installer context has nothing in it, lookups will fail installer_context = InstallerContext() installer_context.set_os_override('ubuntu', 'lucid') try: lookup.resolve('testtinyxml', 'rospack_fake', installer_context) assert False, "should have raised" except ResolutionError as e: assert "Unsupported OS" in str(e), str(e) try: lookup.resolve('fakedep', 'rospack_fake', installer_context) assert False, "should have raised" except ResolutionError as e: assert "Cannot locate rosdep definition" in str(e), str(e) def test_RosdepLookup_resolve(): from rosdep2 import create_default_installer_context from rosdep2.lookup import RosdepLookup rospack, rosstack = get_test_rospkgs() sources_loader = create_test_SourcesListLoader() lookup = RosdepLookup.create_from_rospkg(rospack=rospack, rosstack=rosstack, sources_loader=sources_loader) installer_context = create_default_installer_context() installer_context.set_os_override('ubuntu', 'lucid') # repeat for caching for count in range(0, 2): installer_key, resolution, dependencies = lookup.resolve('testtinyxml', 'rospack_fake', installer_context) assert 'apt' == installer_key assert ['libtinyxml-dev'] == resolution assert [] == dependencies installer_key, resolution, dependencies = lookup.resolve('testboost', 'roscpp_fake', installer_context) assert 'apt' == installer_key assert ['libboost1.40-all-dev'] == resolution assert [] == dependencies installer_key, resolution, dependencies = lookup.resolve('testlibtool', 'roscpp_fake', installer_context) assert 'apt' == installer_key assert set(['libtool', 'libltdl-dev']) == set(resolution) assert [] == dependencies def test_RosdepLookup_resolve_all(): from rosdep2 import create_default_installer_context from rosdep2.lookup import RosdepLookup rospack, rosstack = get_test_rospkgs() sources_loader = create_test_SourcesListLoader() lookup = RosdepLookup.create_from_rospkg(rospack=rospack, rosstack=rosstack, sources_loader=sources_loader) installer_context = create_default_installer_context() installer_context.set_os_override('ubuntu', 'lucid') # repeat for caching lookup.verbose = True for count in range(0, 2): resolutions, errors = lookup.resolve_all(['rospack_fake', 'roscpp_fake'], installer_context) assert not errors, errors installer_keys, resolveds = zip(*resolutions) assert 'apt' in installer_keys apt_resolutions = [] for k, v in resolutions: if k == 'apt': apt_resolutions.extend(v) assert set(apt_resolutions) == set(['libtinyxml-dev', 'libboost1.40-all-dev', 'libtool', 'libltdl-dev']), set(apt_resolutions) ros-rosdep-0.11.4/test/test_rosdep_main.py000066400000000000000000000226611260171354700205770ustar00rootroot00000000000000# 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 the 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. import os import sys try: from cStringIO import StringIO except ImportError: from io import StringIO import rospkg import rospkg.os_detect import unittest from mock import patch from mock import DEFAULT GITHUB_BASE_URL = 'https://github.com/ros/rosdistro/raw/master/rosdep/base.yaml' GITHUB_PYTHON_URL = 'https://github.com/ros/rosdistro/raw/master/rosdep/python.yaml' def get_test_dir(): return os.path.abspath(os.path.dirname(__file__)) def get_test_tree_dir(): return os.path.abspath(os.path.join(get_test_dir(), 'tree')) def get_cache_dir(): p = os.path.join(get_test_dir(), 'sources_cache') assert os.path.isdir(p) return p from rosdep2 import main from rosdep2.main import rosdep_main from rosdep2.main import setup_proxy_opener from contextlib import contextmanager @contextmanager def fakeout(): realstdout = sys.stdout realstderr = sys.stderr fakestdout = StringIO() fakestderr = StringIO() sys.stdout = fakestdout sys.stderr = fakestderr yield fakestdout, fakestderr sys.stdout = realstdout sys.stderr = realstderr # the goal of these tests is only to test that we are wired into the # APIs. More exhaustive tests are at the unit level. class TestRosdepMain(unittest.TestCase): def setUp(self): if 'ROSDEP_DEBUG' in os.environ: del os.environ['ROSDEP_DEBUG'] self.old_rr = rospkg.get_ros_root() self.old_rpp = rospkg.get_ros_package_path() if 'ROS_ROOT' in os.environ: del os.environ['ROS_ROOT'] os.environ['ROS_PACKAGE_PATH'] = os.path.join(get_test_tree_dir()) def tearDown(self): if self.old_rr is not None: os.environ['ROS_ROOT'] = self.old_rr if self.old_rpp is not None: os.environ['ROS_PACKAGE_PATH'] = self.old_rpp def test_bad_commands(self): sources_cache = get_cache_dir() cmd_extras = ['-c', sources_cache] for commands in [[], ['fake', 'something'], ['check'], ['install', '-a', 'rospack_fake'], ['check', 'rospack_fake', '--os', 'ubuntulucid'], ]: try: rosdep_main(commands+cmd_extras) assert False, "system exit should have occurred" except SystemExit: pass def test_check(self): sources_cache = get_cache_dir() cmd_extras = ['-c', sources_cache] with fakeout() as b: try: rosdep_main(['check', 'python_dep']+cmd_extras) except SystemExit: assert False, "system exit occurred: %s\n%s"%(b[0].getvalue(), b[1].getvalue()) stdout, stderr = b assert stdout.getvalue().strip() == "All system dependencies have been satisified", stdout.getvalue() assert not stderr.getvalue(), stderr.getvalue() try: osd = rospkg.os_detect.OsDetect() override = "%s:%s"%(osd.get_name(), osd.get_codename()) with fakeout() as b: rosdep_main(['check', 'python_dep', '--os', override]+cmd_extras) stdout, stderr = b assert stdout.getvalue().strip() == "All system dependencies have been satisified" assert not stderr.getvalue(), stderr.getvalue() except SystemExit: assert False, "system exit occurred" # this used to abort, but now rosdep assumes validity for even empty stack args try: with fakeout() as b: rosdep_main(['check', 'packageless']+cmd_extras) stdout, stderr = b assert stdout.getvalue().strip() == "All system dependencies have been satisified" assert not stderr.getvalue(), stderr.getvalue() except SystemExit: assert False, "system exit occurred" try: rosdep_main(['check', 'nonexistent']+cmd_extras) assert False, "system exit should have occurred" except SystemExit: pass def test_install(self): sources_cache = get_cache_dir() cmd_extras = ['-c', sources_cache] try: # python must have already been installed with fakeout() as b: rosdep_main(['install', 'python_dep']+cmd_extras) stdout, stderr = b assert "All required rosdeps installed" in stdout.getvalue(), stdout.getvalue() assert not stderr.getvalue(), stderr.getvalue() with fakeout() as b: rosdep_main(['install', 'python_dep', '-r']+cmd_extras) stdout, stderr = b assert "All required rosdeps installed" in stdout.getvalue(), stdout.getvalue() assert not stderr.getvalue(), stderr.getvalue() except SystemExit: assert False, "system exit occurred: "+b[1].getvalue() try: rosdep_main(['check', 'nonexistent']) assert False, "system exit should have occurred" except SystemExit: pass def test_where_defined(self): try: sources_cache = get_cache_dir() expected = GITHUB_PYTHON_URL for command in (['where_defined', 'testpython'], ['where_defined', 'testpython']): with fakeout() as b: # set os to ubuntu so this test works on different platforms rosdep_main(command + ['-c', sources_cache, '--os=ubuntu:lucid']) stdout, stderr = b output = stdout.getvalue().strip() assert output == expected, output except SystemExit: assert False, "system exit occurred" def test_what_needs(self): try: sources_cache = get_cache_dir() cmd_extras = ['-c', sources_cache] expected = ['python_dep'] with fakeout() as b: rosdep_main(['what-needs', 'testpython']+cmd_extras) stdout, stderr = b output = stdout.getvalue().strip() assert output.split('\n') == expected expected = ['python_dep'] with fakeout() as b: rosdep_main(['what_needs', 'testpython', '--os', 'ubuntu:lucid', '--verbose']+cmd_extras) stdout, stderr = b output = stdout.getvalue().strip() assert output.split('\n') == expected except SystemExit: assert False, "system exit occurred" def test_keys(self): sources_cache = get_cache_dir() cmd_extras = ['-c', sources_cache] try: with fakeout() as b: rosdep_main(['keys', 'rospack_fake']+cmd_extras) stdout, stderr = b assert stdout.getvalue().strip() == "testtinyxml", stdout.getvalue() assert not stderr.getvalue(), stderr.getvalue() with fakeout() as b: rosdep_main(['keys', 'rospack_fake', '--os', 'ubuntu:lucid', '--verbose']+cmd_extras) stdout, stderr = b assert stdout.getvalue().strip() == "testtinyxml", stdout.getvalue() except SystemExit: assert False, "system exit occurred" try: rosdep_main(['keys', 'nonexistent']+cmd_extras) assert False, "system exit should have occurred" except SystemExit: pass @patch('rosdep2.main.install_opener') @patch('rosdep2.main.build_opener') @patch('rosdep2.main.HTTPBasicAuthHandler') @patch('rosdep2.main.ProxyHandler') def test_proxy_detection(self, proxy, bah, build, install): with patch.dict('os.environ', {'http_proxy': 'something'}, clear=True): setup_proxy_opener() proxy.assert_called_with({'http': 'something'}) with patch.dict('os.environ', {'https_proxy': 'somethings'}, clear=True): setup_proxy_opener() proxy.assert_called_with({'https': 'somethings'}) ros-rosdep-0.11.4/test/test_rosdep_model.py000066400000000000000000000071371260171354700207540ustar00rootroot00000000000000# Copyright (c) 2011, 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 the 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. def test_RosdepDatabaseEntry(): # not muich to test with container from rosdep2.model import RosdepDatabaseEntry d = RosdepDatabaseEntry({'a': 1}, [], 'foo') assert d.rosdep_data == {'a': 1} assert d.view_dependencies == [] assert d.origin == 'foo' def test_RosdepDatabase(): from rosdep2.model import RosdepDatabase db = RosdepDatabase() assert not db.is_loaded('foo') data = {'a': 1} db.set_view_data('foo', data, [], 'origin1') assert db.is_loaded('foo') entry = db.get_view_data('foo') assert entry.rosdep_data == data assert entry.origin == 'origin1' assert entry.view_dependencies == [] # make sure data is copy data['a'] = 2 assert entry.rosdep_data != data data = {'b': 2} db.set_view_data('bar', data, ['foo'], 'origin2') assert db.is_loaded('bar') entry = db.get_view_data('bar') assert entry.rosdep_data == data assert entry.origin == 'origin2' assert entry.view_dependencies == ['foo'] # override entry for bar data = {'b': 3} assert db.is_loaded('bar') db.set_view_data('bar', data, ['baz', 'blah'], 'origin3') assert db.is_loaded('bar') entry = db.get_view_data('bar') assert entry.rosdep_data == data assert entry.origin == 'origin3' assert set(entry.view_dependencies) == set(['baz', 'blah']) def test_RosdepDatabase_get_view_dependencies(): from rosdep2.model import RosdepDatabase data = {'a': 1} db = RosdepDatabase() db.set_view_data('foo', data, [], 'origin') assert [] == db.get_view_dependencies('foo') db.set_view_data('bar', data, ['foo'], 'origin') assert ['foo'] == db.get_view_dependencies('bar') db.set_view_data('baz', data, ['bar'], 'origin') assert ['foo', 'bar'] == db.get_view_dependencies('baz') db.set_view_data('rad', data, [], 'origin') db.set_view_data('fad', data, ['baz', 'rad'], 'origin') retval = db.get_view_dependencies('fad') assert set(['baz', 'rad', 'foo', 'bar']) == set(retval), retval assert len(retval) == 4 ros-rosdep-0.11.4/test/test_rosdep_opensuse.py000066400000000000000000000051471260171354700215140ustar00rootroot00000000000000# Copyright (c) 2011, 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 the 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. # Author Ken Conley/kwc@willowgarage.com import os import traceback from mock import patch def get_test_dir(): # not used yet return os.path.abspath(os.path.join(os.path.dirname(__file__), 'opensuse')) def test_ZypperInstaller(): from rosdep2.platforms.opensuse import ZypperInstaller @patch.object(ZypperInstaller, 'get_packages_to_install') def test(mock_method): installer = ZypperInstaller() mock_method.return_value = [] assert [] == installer.get_install_command(['fake']) # no interactive option with YUM mock_method.return_value = ['a', 'b'] expected = [['sudo', '-H', 'zypper', 'install', '-yl', 'a', 'b']] val = installer.get_install_command(['whatever'], interactive=False) assert val == expected, val expected = [['sudo', '-H', 'zypper', 'install', 'a', 'b']] val = installer.get_install_command(['whatever'], interactive=True) assert val == expected, val try: test() except AssertionError: traceback.print_exc() raise ros-rosdep-0.11.4/test/test_rosdep_osx.py000066400000000000000000000157771260171354700204760ustar00rootroot00000000000000# -*- coding: utf-8 -*- # Copyright (c) 2011, 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 the 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. # Author Ken Conley/kwc@willowgarage.com import os import traceback from mock import call from mock import Mock from mock import patch def get_test_dir(): return os.path.abspath(os.path.join(os.path.dirname(__file__), 'osx')) def is_port_installed_tripwire(): # don't know the correct answer, but make sure this does not throw from rosdep2.platforms.osx import is_port_installed assert is_port_installed() in [True, False] def is_brew_installed_tripwire(): # don't know the correct answer, but make sure this does not throw from rosdep2.platforms.osx import is_brew_installed assert is_brew_installed() in [True, False] def make_resolutions(package_list): from rosdep2.platforms.osx import HomebrewResolution return list(map(lambda pkg: HomebrewResolution(pkg, [], []), package_list)) def make_resolutions_options(package_list): from rosdep2.platforms.osx import HomebrewResolution return list(map(lambda pkg: HomebrewResolution(pkg[0], pkg[1], pkg[2]), package_list)) def brew_command(command): if command[1] == "list": with open(os.path.join(get_test_dir(), 'brew-list-output'), 'r') as f: return f.read() elif command[1] == "info": pkg = command[2] with open(os.path.join(get_test_dir(), 'brew-info-output'), 'r') as f: output = f.readlines() for line in output: res = line.split(":", 1) if res[0] == pkg: return res[1] return '' def test_brew_detect(): from rosdep2.platforms.osx import brew_detect m = Mock() m.return_value = '' val = brew_detect([], exec_fn=m) assert val == [], val m = Mock() m.return_value = '' val = brew_detect(make_resolutions(['tinyxml']), exec_fn=m) assert val == [], val # make sure our test harness is based on the same implementation m.assert_called_with(['brew', 'list']) assert m.call_args_list == [call(['brew', 'list'])], m.call_args_list m = Mock() m.side_effect = brew_command val = brew_detect(make_resolutions(['apt', 'subversion', 'python', 'bazaar']), exec_fn=m) # make sure it preserves order expected = make_resolutions(['subversion', 'bazaar']) assert set(val) == set(expected), val assert val == expected, val assert len(val) == len(set(val)), val def test_HomebrewInstaller(): from rosdep2.platforms.osx import HomebrewInstaller @patch('rosdep2.platforms.osx.is_brew_installed') @patch.object(HomebrewInstaller, 'remove_duplicate_dependencies') @patch.object(HomebrewInstaller, 'get_packages_to_install') def test(mock_get_packages_to_install, mock_remove_duplicate_dependencies, mock_brew_installed): mock_brew_installed.return_value = True installer = HomebrewInstaller() mock_get_packages_to_install.return_value = [] mock_remove_duplicate_dependencies.return_value = mock_get_packages_to_install.return_value assert [] == installer.get_install_command(make_resolutions(['fake'])) mock_get_packages_to_install.return_value = make_resolutions(['subversion', 'bazaar']) mock_remove_duplicate_dependencies.return_value = mock_get_packages_to_install.return_value expected = [['brew', 'install', 'subversion'], ['brew', 'install', 'bazaar']] # brew is always non-interactive for interactive in [True, False]: val = installer.get_install_command(['whatever'], interactive=interactive) assert val == expected, val expected = [['brew', 'uninstall', '--force', 'subversion'], ['brew', 'install', 'subversion'], ['brew', 'uninstall', '--force', 'bazaar'], ['brew', 'install', 'bazaar']] val = installer.get_install_command(['whatever'], reinstall=True) assert val == expected, val mock_get_packages_to_install.return_value = make_resolutions_options( [('subversion', ['foo', 'bar'], ['baz']), ('bazaar', [], ['--with-quux'])]) mock_remove_duplicate_dependencies.return_value = mock_get_packages_to_install.return_value expected = [['brew', 'install', 'subversion', 'foo', 'bar', 'baz'], ['brew', 'install', 'bazaar', '--with-quux']] val = installer.get_install_command(['whatever']) assert val == expected, val try: mock_get_packages_to_install.return_value = eval("make_resolutions_options([('subversion', [u'f´´ßß', u'öäö'], []), (u'bazaar', [], [u'tüü'])])") except SyntaxError: # Python 3.2, u'...' is not allowed, but string literals are unicode mock_get_packages_to_install.return_value = make_resolutions_options( [('subversion', ['f´´ßß', 'öäö'], []), ('bazaar', [], ["tüü"])]) mock_remove_duplicate_dependencies.return_value = mock_get_packages_to_install.return_value try: expected = eval("[['brew', 'install', 'subversion', u'f´´ßß', u'öäö'], ['brew', 'install', 'bazaar', u'tüü']]") except SyntaxError: # Python 3.2, u'...' is not allowed, but string literals are unicode expected = [['brew', 'install', 'subversion', 'f´´ßß', 'öäö'], ['brew', 'install', 'bazaar', "tüü"]] val = installer.get_install_command(['whatever']) assert val == expected, val try: test() except AssertionError: traceback.print_exc() raise ros-rosdep-0.11.4/test/test_rosdep_pip.py000066400000000000000000000100471260171354700204360ustar00rootroot00000000000000# Copyright (c) 2011, 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 the 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. # Author Ken Conley/kwc@willowgarage.com import os import traceback from mock import Mock, patch def get_test_dir(): return os.path.abspath(os.path.join(os.path.dirname(__file__), 'pip')) def test_pip_detect(): from rosdep2.platforms.pip import pip_detect m = Mock() # test behavior with empty freeze m.return_value = '' val = pip_detect([], exec_fn=m) assert val == [], val val = pip_detect(['paramiko'], exec_fn=m) assert val == [], val # read freeze output into mock exec_fn with open(os.path.join(get_test_dir(), 'freeze_output'), 'r') as f: m.return_value = f.read() val = pip_detect(['paramiko'], exec_fn=m) assert val == ['paramiko'], val val = pip_detect(['paramiko', 'fakito', 'pycrypto'], exec_fn=m) assert val == ['paramiko', 'pycrypto'], val def test_PipInstaller_get_depends(): # make sure PipInstaller supports depends from rosdep2.platforms.pip import PipInstaller installer = PipInstaller() assert ['foo'] == installer.get_depends(dict(depends=['foo'])) def test_PipInstaller(): from rosdep2 import InstallFailed from rosdep2.platforms.pip import PipInstaller @patch('rosdep2.platforms.pip.is_pip_installed') def test_no_pip(mock_method): mock_method.return_value = False try: installer = PipInstaller() installer.get_install_command(['whatever']) assert False, "should have raised" except InstallFailed: pass test_no_pip() @patch('rosdep2.platforms.pip.is_pip_installed') @patch.object(PipInstaller, 'get_packages_to_install') def test(mock_method, mock_is_pip_installed): mock_is_pip_installed.return_value = True installer = PipInstaller() mock_method.return_value = [] assert [] == installer.get_install_command(['fake']) # no interactive option with PIP mock_method.return_value = ['a', 'b'] expected = [['sudo', '-H', 'pip', 'install', '-U', 'a'], ['sudo', '-H', 'pip', 'install', '-U', 'b']] val = installer.get_install_command(['whatever'], interactive=False) assert val == expected, val expected = [['sudo', '-H', 'pip', 'install', '-U', 'a'], ['sudo', '-H', 'pip', 'install', '-U', 'b']] val = installer.get_install_command(['whatever'], interactive=True) assert val == expected, val try: test() except AssertionError: traceback.print_exc() raise ros-rosdep-0.11.4/test/test_rosdep_redhat.py000066400000000000000000000156631260171354700211260ustar00rootroot00000000000000# Copyright (c) 2011, 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 the 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. # Author Ken Conley/kwc@willowgarage.com import os import traceback from mock import patch, Mock def get_test_dir(): # not used yet return os.path.abspath(os.path.join(os.path.dirname(__file__), 'redhat')) def test_rpm_detect(): from rosdep2.platforms.redhat import rpm_detect m = Mock() m.return_value = '' val = rpm_detect([], exec_fn=m) assert val == [], val val = rpm_detect(['tinyxml-dev'], exec_fn=m) assert val == [], val def test_DnfInstaller(): from rosdep2.platforms.redhat import DnfInstaller @patch.object(DnfInstaller, 'get_packages_to_install') def test(mock_method): installer = DnfInstaller() mock_method.return_value = [] assert [] == installer.get_install_command(['fake']) # no interactive option with YUM mock_method.return_value = ['a', 'b'] expected = [['sudo', '-H', 'dnf', '--assumeyes', '--quiet', 'install', 'a', 'b']] val = installer.get_install_command(['whatever'], interactive=False, quiet=True) assert val == expected, val + expected expected = [['sudo', '-H', 'dnf', '--quiet', 'install', 'a', 'b']] val = installer.get_install_command(['whatever'], interactive=True, quiet=True) assert val == expected, val + expected expected = [['sudo', '-H', 'dnf', '--assumeyes', 'install', 'a', 'b']] val = installer.get_install_command(['whatever'], interactive=False, quiet=False) assert val == expected, val + expected expected = [['sudo', '-H', 'dnf', 'install', 'a', 'b']] val = installer.get_install_command(['whatever'], interactive=True, quiet=False) assert val == expected, val + expected try: test() except AssertionError: traceback.print_exc() raise def test_YumInstaller(): from rosdep2.platforms.redhat import YumInstaller @patch.object(YumInstaller, 'get_packages_to_install') def test(mock_method): installer = YumInstaller() mock_method.return_value = [] assert [] == installer.get_install_command(['fake']) # no interactive option with YUM mock_method.return_value = ['a', 'b'] expected = [['sudo', '-H', 'yum', '--assumeyes', '--quiet', '--skip-broken', 'install', 'a', 'b']] val = installer.get_install_command(['whatever'], interactive=False, quiet=True) assert val == expected, val + expected expected = [['sudo', '-H', 'yum', '--quiet', '--skip-broken', 'install', 'a', 'b']] val = installer.get_install_command(['whatever'], interactive=True, quiet=True) assert val == expected, val + expected expected = [['sudo', '-H', 'yum', '--assumeyes', '--skip-broken', 'install', 'a', 'b']] val = installer.get_install_command(['whatever'], interactive=False, quiet=False) assert val == expected, val + expected expected = [['sudo', '-H', 'yum', '--skip-broken', 'install', 'a', 'b']] val = installer.get_install_command(['whatever'], interactive=True, quiet=False) assert val == expected, val + expected try: test() except AssertionError: traceback.print_exc() raise def test_Fedora_variable_installer_key(): from rosdep2 import InstallerContext from rosdep2.platforms import pip, redhat, source from rosdep2.platforms.redhat import DNF_INSTALLER, YUM_INSTALLER from rospkg.os_detect import OsDetect, OS_FEDORA os_detect_mock = Mock(spec=OsDetect) os_detect_mock.get_name.return_value = 'fedora' os_detect_mock.get_codename.return_value = 'twenty' os_detect_mock.get_version.return_value = '21' # create our test fixture. use most of the default toolchain, but # replace the apt installer with one that we can have more fun # with. we will do all tests with ubuntu lucid keys -- other # tests should cover different resolution cases. context = InstallerContext(os_detect_mock) pip.register_installers(context) redhat.register_installers(context) source.register_installers(context) redhat.register_platforms(context) assert YUM_INSTALLER == context.get_default_os_installer_key(OS_FEDORA) os_detect_mock.get_version.return_value = '22' assert DNF_INSTALLER == context.get_default_os_installer_key(OS_FEDORA) def test_Fedora_variable_lookup_key(): from rosdep2 import InstallerContext from rosdep2.platforms import pip, redhat, source from rosdep2.platforms.redhat import DNF_INSTALLER, YUM_INSTALLER from rospkg.os_detect import OsDetect, OS_FEDORA os_detect_mock = Mock(spec=OsDetect) os_detect_mock.get_name.return_value = 'fedora' os_detect_mock.get_codename.return_value = 'heisenbug' os_detect_mock.get_version.return_value = '20' # create our test fixture. use most of the default toolchain, but # replace the apt installer with one that we can have more fun # with. we will do all tests with ubuntu lucid keys -- other # tests should cover different resolution cases. context = InstallerContext(os_detect_mock) pip.register_installers(context) redhat.register_installers(context) source.register_installers(context) redhat.register_platforms(context) assert ('fedora', 'heisenbug') == context.get_os_name_and_version() os_detect_mock.get_codename.return_value = 'twenty' os_detect_mock.get_version.return_value = '21' assert (OS_FEDORA, '21') == context.get_os_name_and_version() ros-rosdep-0.11.4/test/test_rosdep_rep3.py000066400000000000000000000051521260171354700205200ustar00rootroot00000000000000# 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 the 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. import os try: from urllib.request import urlopen except ImportError: from urllib2 import urlopen def get_test_dir(): return os.path.abspath(os.path.join(os.path.dirname(__file__), 'sources.list.d')) def test_url_constants(): from rosdep2.rep3 import REP3_TARGETS_URL for url_name, url in [('REP3_TARGETS_URL', REP3_TARGETS_URL), ]: try: f = urlopen(url) f.read() f.close() except: assert False, "URL [%s][%s] failed to download"%(url_name, url) def test_download_targets_data(): from rosdep2.rep3 import download_targets_data, REP3_TARGETS_URL from rosdep2 import DownloadFailure data = download_targets_data(REP3_TARGETS_URL) assert type(data) is dict assert 'electric' in data assert 'fuerte' in data assert 'lucid' in data['fuerte'] assert 'oneiric' in data['fuerte'] try: download_targets_data(targets_url='http://bad.ros.org/foo.yaml') assert False, "should have raised" except DownloadFailure: pass ros-rosdep-0.11.4/test/test_rosdep_rospkg_loader.py000066400000000000000000000147061260171354700225070ustar00rootroot00000000000000# Copyright (c) 2011, 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 the 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. # Author Ken Conley/kwc@willowgarage.com import os import yaml from mock import Mock from rospkg import RosPack, RosStack def get_test_dir(): return os.path.abspath(os.path.join(os.path.dirname(__file__), 'tree')) def get_rospkg(): # configure inside of the test tree test_dir = get_test_dir() ros_root = os.path.join(test_dir, 'ros') ros_package_path = os.path.join(test_dir, 'stacks') ros_paths = [ros_root, ros_package_path] rospack = RosPack(ros_paths=ros_paths) rosstack = RosStack(ros_paths=ros_paths) return rospack, rosstack def test_RosPkgLoader(): from rospkg import ResourceNotFound from rosdep2.model import RosdepDatabase from rosdep2.rospkg_loader import RosPkgLoader, DEFAULT_VIEW_KEY from rosdep2.loader import InvalidData # Due to rosdep 2/REP 125 changes, this test is a bit overbuilt. # All stacks return the same. # tripwire loader = RosPkgLoader() assert loader._rospack is not None assert loader._rosstack is not None # configure inside of the test tree rospack, rosstack = get_rospkg() ros_root = rosstack.get_path('ros') loader = RosPkgLoader(rospack, rosstack) assert loader._rospack == rospack assert loader._rosstack == rosstack # test with mock db rosdep_db = Mock(spec=RosdepDatabase) rosdep_db.is_loaded.return_value = False # test with no rosdep.yaml stack loader.load_view('empty', rosdep_db) rosdep_db.is_loaded.assert_called_with('empty') rosdep_db.set_view_data.assert_called_with('empty', {}, [], '') # test invalid stack try: loader.load_view('does not exist', rosdep_db) assert False, "should have raised" except ResourceNotFound as e: pass # Test with default view key loader.load_view(DEFAULT_VIEW_KEY, rosdep_db) rosdep_db.set_view_data.assert_called_with(DEFAULT_VIEW_KEY, {}, [], '') # test with complicated ros stack. loader.load_view('ros', rosdep_db) rosdep_db.is_loaded.assert_called_with('ros') rosdep_db.set_view_data.assert_called_with('ros', {}, [], '') # test call on db that is already loaded rosdep_db.reset_mock() rosdep_db.is_loaded.return_value = True loader.load_view('ros', rosdep_db) rosdep_db.is_loaded.assert_called_with('ros') assert rosdep_db.set_view_data.call_args_list == [] # test get_view_key, always the same return value assert loader.get_view_key('stack1_p1') == DEFAULT_VIEW_KEY assert loader.get_view_key('stackless') == DEFAULT_VIEW_KEY try: loader.get_view_key('fake') assert False, "should error" except ResourceNotFound: pass def test_RosPkgLoader_with_underlay_key(): from rospkg import ResourceNotFound from rosdep2.model import RosdepDatabase from rosdep2.rospkg_loader import RosPkgLoader, DEFAULT_VIEW_KEY from rosdep2.loader import InvalidData # configure inside of the test tree rospack, rosstack = get_rospkg() ros_root = rosstack.get_path('ros') loader = RosPkgLoader(rospack, rosstack, underlay_key='underlay-key') assert loader._rospack == rospack assert loader._rosstack == rosstack # test with mock db rosdep_db = Mock(spec=RosdepDatabase) rosdep_db.is_loaded.return_value = False # test with no rosdep.yaml stack loader.load_view('empty', rosdep_db) rosdep_db.is_loaded.assert_called_with('empty') rosdep_db.set_view_data.assert_called_with('empty', {}, ['underlay-key'], '') # test invalid stack try: loader.load_view('does not exist', rosdep_db) assert False, "should have raised" except ResourceNotFound as e: pass # test with complicated ros stack. loader.load_view('ros', rosdep_db) rosdep_db.is_loaded.assert_called_with('ros') rosdep_db.set_view_data.assert_called_with('ros', {}, ['underlay-key'], '') # test call on db that is already loaded rosdep_db.reset_mock() rosdep_db.is_loaded.return_value = True loader.load_view('ros', rosdep_db) rosdep_db.is_loaded.assert_called_with('ros') assert rosdep_db.set_view_data.call_args_list == [] # test get_view_key assert loader.get_view_key('stack1_p1') == DEFAULT_VIEW_KEY assert loader.get_view_key('stackless') == DEFAULT_VIEW_KEY try: loader.get_view_key('fake') assert False, "should error" except ResourceNotFound: pass def test_RosPkgLoader_get_loadable(): from rosdep2.rospkg_loader import RosPkgLoader rospack, rosstack = get_rospkg() loader = RosPkgLoader(rospack, rosstack) assert loader._rospack == rospack assert loader._rosstack == rosstack keys = loader.get_loadable_resources() for p in ['stack1_p1', 'stack1_p2', 'stack1_p3']: assert p in keys keys = loader.get_loadable_views() for s in ['ros', 'empty', 'invalid', 'stack1']: assert s in keys ros-rosdep-0.11.4/test/test_rosdep_shell_utils.py000066400000000000000000000040501260171354700221720ustar00rootroot00000000000000# Copyright (c) 2011, 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 the 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. def test_create_tempfile_from_string_and_execute(): # not sure how to test this just yet, for now just a tripwire from rosdep2.shell_utils import create_tempfile_from_string_and_execute assert create_tempfile_from_string_and_execute('#!/bin/sh\necho "hello"'), "ls command failed" assert not create_tempfile_from_string_and_execute('bad'), "bad command did not fail" def test_read_stdout(): from rosdep2.shell_utils import read_stdout assert 'foo' in read_stdout(['echo', 'foo']) ros-rosdep-0.11.4/test/test_rosdep_source.py000066400000000000000000000256071260171354700211560ustar00rootroot00000000000000# Copyright (c) 2011, 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 the 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. # Author Ken Conley/kwc@willowgarage.com import os import yaml rep122_install_command = """#!/bin/bash set -o errexit mkdir -p build cd build cmake .. make echo "About to run checkinstall make install" sudo checkinstall -y --nodoc --pkgname=yaml-cpp-sourcedep make install """ rep122_check_presence_command = """#!/bin/bash dpkg-query -W -f='${Package} ${Status}\\n' yaml-cpp-sourcedep | awk '{\\ if ($4 =="installed") exit 0 else print "yaml-cpp-sourcedep not installed" exit 1}' """ REP112_MD5SUM = '77040d44b0e620c092bce918ac7b4180' def get_test_dir(): return os.path.abspath(os.path.join(os.path.dirname(__file__), 'source')) def _subtest_rep112_rdmanifest(resolved): test_dir = get_test_dir() path = os.path.join(test_dir, 'rep112-example.rdmanifest') manifest = yaml.load(open(path)) assert resolved.manifest == manifest assert resolved.manifest_url == path assert resolved.install_command == rep122_install_command assert resolved.check_presence_command == rep122_check_presence_command assert len(resolved.check_presence_command) == len(rep122_check_presence_command), "%s %s"%(len(resolved.check_presence_command), len(rep122_check_presence_command)) assert resolved.exec_path == 'yaml-cpp-0.2.5' assert resolved.tarball == 'https://yaml-cpp.googlecode.com/files/yaml-cpp-0.2.5.tar.gz' assert resolved.alternate_tarball == None assert resolved.tarball_md5sum == 'b17dc36055cd2259c88b2602601415d9' def test_SourceInstall(): from rosdep2.platforms.source import InvalidRdmanifest, SourceInstall #tripwire SourceInstall() # test unpacking of dict manifest = { 'md5sum': 'fake-md5', 'exec-path': '/path', 'install-script': 'echo hello', 'check-presence-script': 'hello there', 'uri': 'http://ros.org/', 'alternate-uri': 'http://turtlebot.com/', 'depends': ['foo', 'bar'], } resolved = SourceInstall.from_manifest(manifest, 'fake-url') assert resolved.manifest == manifest assert resolved.manifest_url == 'fake-url' assert resolved.install_command == 'echo hello' assert resolved.check_presence_command == 'hello there' assert resolved.exec_path == '/path' assert resolved.tarball == 'http://ros.org/' assert resolved.alternate_tarball == 'http://turtlebot.com/' assert resolved.tarball_md5sum == 'fake-md5' test_dir = get_test_dir() path = os.path.join(test_dir, 'rep112-example.rdmanifest') manifest = yaml.load(open(path)) resolved = SourceInstall.from_manifest(manifest, path) _subtest_rep112_rdmanifest(resolved) #TODO: test depends # test with bad dicts manifest = { 'md5sum': 'fake-md5', 'exec-path': '/path', 'install-script': 'echo hello', 'check-presence-script': 'hello there', 'alternate-uri': 'http://turtlebot.com/', 'depends': ['foo', 'bar'], } # uri is required try: SourceInstall.from_manifest(manifest, 'foo') assert False, "should have raised" except InvalidRdmanifest as e: pass # test defaults manifest = dict(uri='http://ros.org/') resolved = SourceInstall.from_manifest(manifest, 'foo') assert resolved.exec_path == '.' assert resolved.install_command == '' assert resolved.check_presence_command == '' assert resolved.alternate_tarball is None assert resolved.tarball_md5sum is None def test_is_installed(): from rosdep2.platforms.source import SourceInstaller, SourceInstall resolved = SourceInstall() resolved.check_presence_command = """#!/bin/bash exit 0 """ installer = SourceInstaller() assert installer.is_installed(resolved) def test_source_detect(): from rosdep2.platforms.source import source_detect, SourceInstall resolved = SourceInstall() resolved.check_presence_command = """#!/bin/bash exit 0 """ assert [] == source_detect([]) assert [resolved] == source_detect([resolved]) def yes(*args, **kwds): return 0 def no(*args, **kwds): return 1 resolved = [SourceInstall(), SourceInstall(), SourceInstall(), SourceInstall()] for r in resolved: r.check_presence_command = '' retval = source_detect(resolved, exec_fn=yes) assert resolved == retval, retval assert [] == source_detect(resolved, exec_fn=no) def test_SourceInstaller_get_install_command(): from rosdep2.platforms.source import SourceInstaller, SourceInstall installer = SourceInstaller() resolved = SourceInstall() resolved.manifest_url = 'http://fake/foo' resolved.check_presence_command = """#!/bin/bash exit 1 """ commands = installer.get_install_command([resolved]) assert len(commands) == 1 assert commands[0] == ['rosdep-source', 'install', 'http://fake/foo'] resolved = SourceInstall() resolved.manifest_url = 'http://fake/foo' resolved.check_presence_command = """#!/bin/bash exit 0 """ commands = installer.get_install_command([resolved]) assert not(commands) def test_SourceInstaller_resolve(): from rosdep2.platforms.source import SourceInstaller, InvalidData test_dir = get_test_dir() url = 'file://%s' % os.path.join(test_dir, 'rep112-example.rdmanifest') md5sum_good = REP112_MD5SUM md5sum_bad = 'fake' installer = SourceInstaller() try: installer.resolve({}) assert False, "should have raised" except InvalidData: pass try: installer.resolve(dict(uri=url, md5sum=md5sum_bad)) assert False, "should have raised" except InvalidData: pass resolved = installer.resolve(dict(uri=url, md5sum=md5sum_good)) assert type(resolved) == list assert len(resolved) == 1 # test for reinstall (to check the depends in rdmanifest) dependencies = installer.get_depends(dict(uri=url, md5sum=md5sum_good)) assert dependencies == ['checkinstall'], "Dependencies should resolve to checkinstall listed in the rdmanifest." resolved = resolved[0] assert resolved.install_command == rep122_install_command assert resolved.check_presence_command == rep122_check_presence_command # test again to activate caching resolved = installer.resolve(dict(uri=url, md5sum=md5sum_good)) assert type(resolved) == list, "Cache should also return a list" assert len(resolved) == 1 resolved = resolved[0] assert resolved.install_command == rep122_install_command assert resolved.check_presence_command == rep122_check_presence_command def test_load_rdmanifest(): from rosdep2.platforms.source import load_rdmanifest, InvalidRdmanifest # load_rdmanifest is just a YAML unmarshaller with an exception change assert 'str' == load_rdmanifest('str') assert {'a': 'b'} == load_rdmanifest('{a: b}') try: load_rdmanifest(';lkajsdf;klj ;l: a;kljdf;: asdf\n ;asdfl;kj') assert False, "should have raised" except InvalidRdmanifest as e: pass def test_get_file_hash(): from rosdep2.platforms.source import get_file_hash path = os.path.join(get_test_dir(), 'rep112-example.rdmanifest') assert REP112_MD5SUM == get_file_hash(path) def test_fetch_file(): test_dir = get_test_dir() with open(os.path.join(test_dir, 'rep112-example.rdmanifest')) as f: expected = f.read() from rosdep2.platforms.source import fetch_file url = 'file://%s' % os.path.join(test_dir, 'rep112-example.rdmanifest') contents, error = fetch_file(url, REP112_MD5SUM) assert not error assert contents == expected contents, error = fetch_file(url, 'badmd5') assert bool(error), "should have errored" assert not contents contents, error = fetch_file('http://badhostname.willowgarage.com', 'md5sum') assert not contents assert bool(error), "should have errored" def test_download_rdmanifest(): test_dir = get_test_dir() with open(os.path.join(test_dir, 'rep112-example.rdmanifest')) as f: expected = yaml.load(f) from rosdep2.platforms.source import download_rdmanifest, DownloadFailed url = 'file://%s' % os.path.join(test_dir, 'rep112-example.rdmanifest') contents, download_url = download_rdmanifest(url, REP112_MD5SUM) assert contents == expected assert download_url == url # test alt_url contents, download_url = download_rdmanifest('http://badhostname.willowgarage.com/', REP112_MD5SUM, alt_url=url) assert contents == expected assert download_url == url # test md5sum validate try: contents, error = download_rdmanifest(url, 'badmd5') assert False, "should have errored" except DownloadFailed: pass # test download verify try: contents, error = download_rdmanifest('http://badhostname.willowgarage.com', 'fakemd5') assert False, "should have errored" except DownloadFailed: pass def test_install_from_file(): from rosdep2.platforms.source import install_from_file f = os.path.join(get_test_dir(), 'noop-not-installed.rdmanifest') install_from_file(f) def test_install_source(): from rosdep2.platforms.source import install_source, SourceInstall resolved = SourceInstall() resolved.tarball = 'https://github.com/ros-infrastructure/rosdep/raw/master/test/source/foo.tar.gz' resolved.tarball_md5sum = 'fd34dc39f8f192b97fcc191fe0a6befc' resolved.install_command = """#!/bin/sh exit 0 """ resolved.exec_path = '' install_source(resolved) ros-rosdep-0.11.4/test/test_rosdep_sources_list.py000066400000000000000000000452331260171354700223710ustar00rootroot00000000000000# 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 the 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. import os import tempfile import yaml try: from urllib.request import urlopen from urllib.error import URLError except ImportError: from urllib2 import urlopen from urllib2 import URLError import rospkg.distro import rosdep2.sources_list GITHUB_BASE_URL = 'https://raw.github.com/ros/rosdistro/master/rosdep/base.yaml' def get_test_dir(): return os.path.abspath(os.path.join(os.path.dirname(__file__), 'sources.list.d')) def test_get_sources_list_dir(): assert rosdep2.sources_list.get_sources_list_dir() def test_get_sources_cache_dir(): assert rosdep2.sources_list.get_sources_cache_dir() def test_parse_sources_data(): from rosdep2.sources_list import parse_sources_data parse_sources_data def test_url_constants(): from rosdep2.sources_list import DEFAULT_SOURCES_LIST_URL for url_name, url in [('DEFAULT_SOURCES_LIST_URL', DEFAULT_SOURCES_LIST_URL)]: try: f = urlopen(url) f.read() f.close() except: assert False, "URL [%s][%s] failed to download"%(url_name, url) def test_download_default_sources_list(): from rosdep2.sources_list import download_default_sources_list data = download_default_sources_list() assert 'http' in data, data # sanity check, all sources files have urls try: download_default_sources_list(url='http://bad.ros.org/foo.yaml') assert False, "should not have succeeded/valdiated" except URLError: pass def test_CachedDataSource(): from rosdep2.sources_list import CachedDataSource, DataSource, TYPE_GBPDISTRO, TYPE_YAML type_ = TYPE_GBPDISTRO url = 'http://fake.willowgarage.com/foo' tags = ['tag1'] rosdep_data = {'key': {}} origin = '/tmp/bar' cds = CachedDataSource(type_, url, tags, rosdep_data, origin=origin) assert cds == CachedDataSource(type_, url, tags, rosdep_data, origin=origin) assert cds != CachedDataSource(type_, url, tags, rosdep_data, origin=None) assert cds != CachedDataSource(type_, url, tags, {}, origin=origin) assert cds != CachedDataSource(TYPE_YAML, url, tags, rosdep_data, origin=origin) assert cds != CachedDataSource(type_, 'http://ros.org/foo.yaml', tags, rosdep_data, origin=origin) assert cds != DataSource(type_, url, tags, origin=origin) assert DataSource(type_, url, tags, origin=origin) != cds assert cds.type == type_ assert cds.url == url assert cds.origin == origin assert cds.rosdep_data == rosdep_data assert type_ in str(cds) assert type_ in repr(cds) assert url in str(cds) assert url in repr(cds) assert tags[0] in str(cds) assert tags[0] in repr(cds) assert 'key' in str(cds) assert 'key' in repr(cds) def test_DataSource(): from rosdep2.sources_list import DataSource data_source = DataSource('yaml', 'http://fake/url', ['tag1', 'tag2']) assert data_source == rosdep2.sources_list.DataSource('yaml', 'http://fake/url', ['tag1', 'tag2']) assert 'yaml' == data_source.type assert 'http://fake/url' == data_source.url assert ['tag1', 'tag2'] == data_source.tags assert 'yaml http://fake/url tag1 tag2' == str(data_source) data_source_foo = DataSource('yaml', 'http://fake/url', ['tag1', 'tag2'], origin='foo') assert data_source_foo != data_source assert data_source_foo.origin == 'foo' assert '[foo]:\nyaml http://fake/url tag1 tag2' == str(data_source_foo), str(data_source_foo) assert repr(data_source) try: rosdep2.sources_list.DataSource('yaml', 'http://fake/url', 'tag1', origin='foo') assert False, "should have raised" except ValueError: pass try: rosdep2.sources_list.DataSource('yaml', 'non url', ['tag1'], origin='foo') assert False, "should have raised" except ValueError: pass try: rosdep2.sources_list.DataSource('bad', 'http://fake/url', ['tag1'], origin='foo') assert False, "should have raised" except ValueError: pass try: rosdep2.sources_list.DataSource('yaml', 'http://host.no.path/', ['tag1'], origin='foo') assert False, "should have raised" except ValueError: pass def test_parse_sources_file(): from rosdep2.sources_list import parse_sources_file from rosdep2 import InvalidData for f in ['20-default.list', '30-nonexistent.list']: path = os.path.join(get_test_dir(), f) sources = parse_sources_file(path) assert sources[0].type == 'yaml' assert sources[0].origin == path, sources[0].origin try: sources = parse_sources_file('bad') except InvalidData: pass def test_parse_sources_list(): from rosdep2.sources_list import parse_sources_list from rosdep2 import InvalidData # test with non-existent dir, should return with empty list as # directory is not required to exist. assert [] == parse_sources_list(sources_list_dir='/not/a/real/path') # test with real dir path = get_test_dir() sources_list = parse_sources_list(sources_list_dir=get_test_dir()) # at time test was written, at least two sources files assert len(sources_list) > 1 # make sure files got loaded in intended order assert sources_list[0].origin.endswith('20-default.list') assert sources_list[1].origin.endswith('20-default.list') assert sources_list[2].origin.endswith('30-nonexistent.list') # tripwire -- we don't know what the actual return value is, but # should not error on a correctly configured test system. parse_sources_list() def test_write_cache_file(): from rosdep2.sources_list import write_cache_file, compute_filename_hash, PICKLE_CACHE_EXT try: import cPickle as pickle except ImportError: import pickle tempdir = tempfile.mkdtemp() filepath = write_cache_file(tempdir, 'foo', {'data': 1}) + PICKLE_CACHE_EXT computed_path = os.path.join(tempdir, compute_filename_hash('foo')) + PICKLE_CACHE_EXT assert os.path.samefile(filepath, computed_path) with open(filepath, 'rb') as f: assert {'data': 1} == pickle.loads(f.read()) def test_update_sources_list(): from rosdep2.sources_list import update_sources_list, InvalidData, compute_filename_hash, PICKLE_CACHE_EXT try: import cPickle as pickle except ImportError: import pickle try: from urllib.request import pathname2url except ImportError: from urllib import pathname2url sources_list_dir=get_test_dir() index_path = os.path.abspath(os.path.join(os.path.dirname(__file__), 'rosdistro', 'index.yaml')) index_url = 'file://' + pathname2url(index_path) os.environ['ROSDISTRO_INDEX_URL'] = index_url tempdir = tempfile.mkdtemp() # use a subdirectory of test dir to make sure rosdep creates the necessary substructure tempdir = os.path.join(tempdir, 'newdir') errors = [] def error_handler(loc, e): errors.append((loc, e)) retval = update_sources_list(sources_list_dir=sources_list_dir, sources_cache_dir=tempdir, error_handler=error_handler) assert retval assert len(retval) == 2, retval # one of our sources is intentionally bad, this should be a softfail assert len(errors) == 1, errors assert errors[0][0].url == 'https://badhostname.willowgarage.com/rosdep.yaml' source0, path0 = retval[0] assert source0.origin.endswith('20-default.list'), source0 hash1 = compute_filename_hash(GITHUB_URL) hash2 = compute_filename_hash(BADHOSTNAME_URL) filepath = os.path.join(tempdir, hash1) assert filepath == path0, "%s vs %s"%(filepath, path0) with open(filepath+PICKLE_CACHE_EXT, 'rb') as f: data = pickle.loads(f.read()) assert 'cmake' in data # verify that cache index exists. contract specifies that even # failed downloads are specified in the index, just in case old # download data is present. with open(os.path.join(tempdir, 'index'), 'r') as f: index = f.read().strip() expected = "#autogenerated by rosdep, do not edit. use 'rosdep update' instead\n"\ "yaml %s \n"\ "yaml %s python\n"\ "yaml %s ubuntu"%(GITHUB_URL, GITHUB_PYTHON_URL, BADHOSTNAME_URL) assert expected == index, "\n[%s]\nvs\n[%s]"%(expected, index) def test_load_cached_sources_list(): from rosdep2.sources_list import load_cached_sources_list, update_sources_list tempdir = tempfile.mkdtemp() # test behavior on empty cache assert [] == load_cached_sources_list(sources_cache_dir=tempdir) # pull in cache data sources_list_dir=get_test_dir() retval = update_sources_list(sources_list_dir=sources_list_dir, sources_cache_dir=tempdir, error_handler=None) assert retval # now test with cached data retval = load_cached_sources_list(sources_cache_dir=tempdir) assert len(retval) == 3, '%s != %s' % ([source0, source1, source2], retval[0:3]) source0 = retval[0] source1 = retval[1] source2 = retval[2] # this should be the 'default' source assert 'python' in source1.rosdep_data assert not source0.tags # this should be the 'non-existent' source assert source2.rosdep_data == {} assert source2.tags == ['ubuntu'] def test_DataSourceMatcher(): empty_data_source = rosdep2.sources_list.DataSource('yaml', 'http://fake/url', []) assert empty_data_source == rosdep2.sources_list.DataSource('yaml', 'http://fake/url', []) # matcher must match 'all' tags data_source = rosdep2.sources_list.DataSource('yaml', 'http://fake/url', ['tag1', 'tag2']) partial_data_source = rosdep2.sources_list.DataSource('yaml', 'http://fake/url', ['tag1']) # same tags as test data source matcher = rosdep2.sources_list.DataSourceMatcher(['tag1', 'tag2']) assert matcher.matches(data_source) assert matcher.matches(partial_data_source) assert matcher.matches(empty_data_source) # alter one tag matcher = rosdep2.sources_list.DataSourceMatcher(['tag1', 'tag3']) assert not matcher.matches(data_source) assert matcher.matches(empty_data_source) matcher = rosdep2.sources_list.DataSourceMatcher(['tag1']) assert not matcher.matches(data_source) def test_download_rosdep_data(): from rosdep2.sources_list import download_rosdep_data from rosdep2 import DownloadFailure url = GITHUB_BASE_URL data = download_rosdep_data(url) assert 'boost' in data #sanity check # try with a bad URL try: data = download_rosdep_data('http://badhost.willowgarage.com/rosdep.yaml') assert False, "should have raised" except DownloadFailure as e: pass # try to trigger both non-dict clause and YAMLError clause for url in [ 'https://code.ros.org/svn/release/trunk/distros/', 'https://code.ros.org/svn/release/trunk/distros/manifest.xml', ]: try: data = download_rosdep_data(url) assert False, "should have raised" except DownloadFailure as e: pass BADHOSTNAME_URL = 'https://badhostname.willowgarage.com/rosdep.yaml' GITHUB_URL = 'https://github.com/ros/rosdistro/raw/master/rosdep/base.yaml' GITHUB_PYTHON_URL = 'https://github.com/ros/rosdistro/raw/master/rosdep/python.yaml' GITHUB_FUERTE_URL = 'https://raw.github.com/ros-infrastructure/rosdep_rules/master/rosdep_fuerte.yaml' EXAMPLE_SOURCES_DATA_BAD_TYPE = "YAML %s"%(GITHUB_URL) EXAMPLE_SOURCES_DATA_BAD_URL = "yaml not-a-url tag1 tag2" EXAMPLE_SOURCES_DATA_BAD_LEN = "yaml" EXAMPLE_SOURCES_DATA_NO_TAGS = "yaml %s"%(GITHUB_URL) EXAMPLE_SOURCES_DATA = "yaml %s fuerte ubuntu"%(GITHUB_URL) EXAMPLE_SOURCES_DATA_MULTILINE = """ # this is a comment, above and below are empty lines yaml %s yaml %s fuerte ubuntu """%(GITHUB_URL, GITHUB_FUERTE_URL) def test_parse_sources_data(): from rosdep2.sources_list import parse_sources_data, TYPE_YAML, InvalidData retval = parse_sources_data(EXAMPLE_SOURCES_DATA, origin='foo') assert len(retval) == 1 sd = retval[0] assert sd.type == TYPE_YAML, sd.type assert sd.url == GITHUB_URL assert sd.tags == ['fuerte', 'ubuntu'] assert sd.origin == 'foo' retval = parse_sources_data(EXAMPLE_SOURCES_DATA_NO_TAGS) assert len(retval) == 1 sd = retval[0] assert sd.type == TYPE_YAML assert sd.url == GITHUB_URL assert sd.tags == [] assert sd.origin == '' retval = parse_sources_data(EXAMPLE_SOURCES_DATA_MULTILINE) assert len(retval) == 2 sd = retval[0] assert sd.type == TYPE_YAML assert sd.url == GITHUB_URL assert sd.tags == [] sd = retval[1] assert sd.type == TYPE_YAML assert sd.url == GITHUB_FUERTE_URL assert sd.tags == ['fuerte', 'ubuntu'] for bad in [EXAMPLE_SOURCES_DATA_BAD_URL, EXAMPLE_SOURCES_DATA_BAD_TYPE, EXAMPLE_SOURCES_DATA_BAD_LEN]: try: parse_sources_data(bad) assert False, "should have raised: %s"%(bad) except InvalidData as e: pass def test_DataSourceMatcher_create_default(): distro_name = rospkg.distro.current_distro_codename() os_detect = rospkg.os_detect.OsDetect() os_name, os_version, os_codename = os_detect.detect_os() matcher = rosdep2.sources_list.DataSourceMatcher.create_default() # matches full os_data_source = rosdep2.sources_list.DataSource('yaml', 'http://fake/url', [distro_name, os_name, os_codename]) assert matcher.matches(os_data_source) # matches against current os os_data_source = rosdep2.sources_list.DataSource('yaml', 'http://fake/url', [os_name, os_codename]) assert matcher.matches(os_data_source) # matches against current distro distro_data_source = rosdep2.sources_list.DataSource('yaml', 'http://fake/url', [distro_name]) assert matcher.matches(distro_data_source) # test matcher with os override matcher = rosdep2.sources_list.DataSourceMatcher.create_default(os_override=('fubuntu', 'flucid')) assert not matcher.matches(os_data_source) data_source = rosdep2.sources_list.DataSource('yaml', 'http://fake/url', ['fubuntu']) assert matcher.matches(data_source) data_source = rosdep2.sources_list.DataSource('yaml', 'http://fake/url', ['flucid']) assert matcher.matches(data_source) data_source = rosdep2.sources_list.DataSource('yaml', 'http://fake/url', ['flucid', 'fubuntu']) assert matcher.matches(data_source) data_source = rosdep2.sources_list.DataSource('yaml', 'http://fake/url', ['kubuntu', 'lucid']) assert not matcher.matches(data_source) def test_SourcesListLoader_create_default(): from rosdep2.sources_list import update_sources_list, SourcesListLoader, DataSourceMatcher # create temp dir for holding sources cache tempdir = tempfile.mkdtemp() # pull in cache data sources_list_dir=get_test_dir() retval = update_sources_list(sources_list_dir=sources_list_dir, sources_cache_dir=tempdir, error_handler=None) assert retval # now test with cached data matcher = rosdep2.sources_list.DataSourceMatcher(['ubuntu', 'lucid']) loader = SourcesListLoader.create_default(matcher, sources_cache_dir=tempdir) assert loader.sources sources0 = loader.sources assert not any([s for s in loader.sources if not matcher.matches(s)]) loader = SourcesListLoader.create_default(matcher, sources_cache_dir=tempdir) assert sources0 == loader.sources # now test with different matcher matcher2 = rosdep2.sources_list.DataSourceMatcher(['python']) loader2 = SourcesListLoader.create_default(matcher2, sources_cache_dir=tempdir) assert loader2.sources # - should have filtered down to python-only assert sources0 != loader2.sources assert not any([s for s in loader2.sources if not matcher2.matches(s)]) # test API # very simple, always raises RNF try: loader.get_rosdeps('foo') except rospkg.ResourceNotFound: pass try: loader.get_view_key('foo') except rospkg.ResourceNotFound: pass assert [] == loader.get_loadable_resources() all_sources = [x.url for x in loader.sources] assert all_sources == loader.get_loadable_views() # test get_source early to make sure model matches expected try: loader.get_source('foo') assert False, "should have raised" except rospkg.ResourceNotFound: pass s = loader.get_source(GITHUB_URL) assert s.url == GITHUB_URL # get_view_dependencies # - loader doesn't new view name, so assume everything assert all_sources == loader.get_view_dependencies('foo') # - actual views don't depend on anything assert [] == loader.get_view_dependencies(GITHUB_URL) # load_view from rosdep2.model import RosdepDatabase for verbose in [True, False]: rosdep_db = RosdepDatabase() loader.load_view(GITHUB_URL, rosdep_db, verbose=verbose) assert rosdep_db.is_loaded(GITHUB_URL) assert [] == rosdep_db.get_view_dependencies(GITHUB_URL) entry = rosdep_db.get_view_data(GITHUB_URL) assert 'cmake' in entry.rosdep_data assert GITHUB_URL == entry.origin # - coverage, repeat loader, should noop loader.load_view(GITHUB_URL, rosdep_db) ros-rosdep-0.11.4/test/tree/000077500000000000000000000000001260171354700156165ustar00rootroot00000000000000ros-rosdep-0.11.4/test/tree/ros/000077500000000000000000000000001260171354700164215ustar00rootroot00000000000000ros-rosdep-0.11.4/test/tree/ros/python_dep/000077500000000000000000000000001260171354700205725ustar00rootroot00000000000000ros-rosdep-0.11.4/test/tree/ros/python_dep/manifest.xml000066400000000000000000000004011260171354700231150ustar00rootroot00000000000000 needs python Ken Conley BSD http://ros.org/wiki/ ros-rosdep-0.11.4/test/tree/ros/roscpp_fake/000077500000000000000000000000001260171354700207155ustar00rootroot00000000000000ros-rosdep-0.11.4/test/tree/ros/roscpp_fake/manifest.xml000066400000000000000000000004341260171354700232460ustar00rootroot00000000000000 roscpp Ken Conley BSD http://ros.org/wiki/roscpp ros-rosdep-0.11.4/test/tree/ros/rosdep.yaml000066400000000000000000000144471260171354700206130ustar00rootroot00000000000000testtinyxml: ubuntu: libtinyxml-dev debian: libtinyxml-dev osx: source: uri: 'http://kforge.ros.org/rosrelease/viewvc/sourcedeps/tinyxml/tinyxml-2.6.2-1.rdmanifest' md5sum: 13760e61e08c9004493c302a16966c42 testpython: ubuntu: python-dev debian: python-dev arch: python opensuse: python-devel fedora: python-devel rhel: python-devel macports: python26 python_select gentoo: python cygwin: python freebsd: python testpython-yaml: ubuntu: python-yaml debian: python-yaml opensuse: python-yaml fedora: PyYAML rhel: PyYAML centos: PyYAML arch: python-yaml macports: py26-yaml gentoo: pyyaml cygwin: | if [ ! -d /usr/lib/python2.5/site-packages/yaml/ ] ; then mkdir -p ~/ros/ros-deps cd ~/ros/ros-deps wget --tries=10 http://pyyaml.org/download/pyyaml/PyYAML-3.09.tar.gz tar xzf PyYAML-3.09.tar.gz cd PyYAML-3.09 python setup.py install fi freebsd: py27-yaml testpython-gtk2: ubuntu: python-gtk2 arch: pygtk debian: python-gtk2 macports: py26-gtk opensuse: python-gtk fedora: pygtk2 rhel: pygtk2 gentoo: "=dev-python/pygtk-2*" freebsd: py-gtk2 testpython-scipy: ubuntu: python-scipy debian: python-scipy arch: python-scipy opensuse: python-scipy fedora: scipy macports: py26-scipy gentoo: dev-libs/scipy freebsd: py-scipy testbzip2: ubuntu: libbz2-dev debian: libbz2-dev opensuse: libbz2-devel fedora: bzip2-devel rhel: bzip2-devel arch: bzip2 macports: bzip2 gentoo: app-arch/bzip2 cygwin: bzip2 freebsd: bzip2 testboost: ubuntu: lucid: apt: packages: [libboost1.40-all-dev] maverick: apt: packages: [libboost1.42-all-dev] natty: apt: packages: [libboost1.42-all-dev] debian: squeeze: libboost1.42-all-dev lenny: | if [ ! -f /opt/ros/lib/libboost_date_time-gcc43-mt*-1_37.a ] ; then mkdir -p ~/ros/ros-deps cd ~/ros/ros-deps wget --tries=10 http://pr.willowgarage.com/downloads/boost_1_37_0.tar.gz tar xzf boost_1_37_0.tar.gz cd boost_1_37_0 ./configure --prefix=/opt/ros make sudo make install fi 3.1: | if [ ! -f /opt/ros/lib/libboost_date_time-gcc33-mt*-1_37.a ] ; then mkdir -p ~/ros/ros-deps cd ~/ros/ros-deps wget --tries=10 http://pr.willowgarage.com/downloads/boost_1_37_0.tar.gz tar xzf boost_1_37_0.tar.gz cd boost_1_37_0 ./configure --prefix=/opt/ros make sudo make install fi opensuse: boost-devel fedora: boost-devel rhel: boost-devel arch: boost macports: boost gentoo: dev-libs/boost cygwin: libboost-devel libboost1.40 freebsd: boost-python-libs testzlib: ubuntu: zlib1g-dev debian: zlib1g-dev opensuse: zlib-devel fedora: zlib-devel rhel: zlib-devel arch: zlib macports: zlib gentoo: sys-libs/zlib cygwin: zlib freebsd: builtin testgraphviz: ubuntu: graphviz debian: graphviz opensuse: graphviz fedora: graphviz rhel: graphviz arch: graphviz macports: graphviz gentoo: media-gfx/graphviz freebsd: graphviz testwxwidgets: ubuntu: libwxgtk2.8-dev debian: libwxgtk2.8-dev opensuse: wxGTK-devel fedora: wxGTK-devel rhel: wxGTK-devel macports: wxWidgets-python arch: wxgtk gentoo: x11-libs/wxGTK freebsd: wxgtk2 testwxpython: ubuntu: python-wxgtk2.8 arch: wxpython opensuse: python-wxGTK fedora: wxPython-devel rhel: wxPython-devel centos: wxPython-devel debian: python-wxgtk2.8 macports: py26-wxpython py26-gobject py26-gtk py26-cairo gentoo: dev-python/wxpython freebsd: py27-wxPython testgtk2: ubuntu: libgtk2.0-dev debian: libgtk2.0-dev opensuse: gtk2-devel fedora: gtk2-devel rhel: gtk2-devel macports: gtk2 arch: gtk2 gentoo: x11-libs/gtk+ freebsd: gtk20 testpkg-config: ubuntu: pkg-config debian: pkg-config opensuse: pkg-config fedora: pkgconfig rhel: pkgconfig arch: pkg-config macports: pkgconfig gentoo: dev-util/pkgconfig cygwin: pkg-config freebsd: pkg-config testqt4: ubuntu: libqt4-dev qt4-dev-tools debian: libqt4-dev qt4-dev-tools arch: qt opensuse: libqt4-devel fedora: qt-devel macports: qt4-mac gentoo: ">=x11-libs/qt-core-4" freebsd: qt4-corelib testlibstdc++5: ubuntu: libstdc++5 debian: libstdc++5 opensuse: libstdc++33 freebsd: builtin testintltool: ubuntu: intltool opensuse: intltool fedora: intltool gentoo: dev-util/intltool freebsd: intltool testunzip: ubuntu: unzip debian: unzip arch: unzip opensuse: unzip fedora: unzip rhel: unzip macports: unzip gentoo: app-arch/unzip freebsd: unzip testfltk: ubuntu: libfltk1.1-dev debian: libfltk1.1-dev opensuse: fltk-devel fedora: fltk-devel arch: fltk macports: fltk gentoo: "=x11-libs/fltk-1*" freebsd: fltk testbazaar: ubuntu: bzr debian: bzr opensuse: bzr fedora: bazaar macports: bazaar gentoo: dev-vcs/bzr freebsd: bazaar testgit: ubuntu: git-core debian: git-core opensuse: git-core fedora: git macports: git-core gentoo: dev-vcs/git freebsd: git testsubversion: ubuntu: subversion debian: subversion opensuse: subversion fedora: subversion macports: subversion gentoo: dev-vcs/subversion freebsd: subversion testmercurial: ubuntu: mercurial debian: mercurial opensuse: mercurial fedora: mercurial macports: mercurial gentoo: dev-vcs/mercurial freebsd: mercurial testgtest: ubuntu: libgtest-dev debian: libgtest-dev opensuse: gtest-devel fedora: gtest-devel macports: google-test gentoo: dev-util/gtest freebsd: googletest testautoconf: ubuntu: autoconf debian: autoconf opensuse: autoconf fedora: autoconf rhel: autoconf arch: autoconf macports: autoconf gentoo: sys-devel/autoconf freebsd: autoconf213 autoconf268 testautomake: ubuntu: automake debian: automake opensuse: automake fedora: automake rhel: automake arch: automake macports: automake gentoo: sys-devel/automake freebsd: automake14 automake111 testlibtool: ubuntu: apt: packages: [libtool, libltdl-dev] debian: squeeze: libtool libltdl-dev lenny: libtool libltdl3-dev opensuse: libtool libltdl3 fedora: libtool libtool-ltdl-devel rhel: libtool libtool-ltdl-devel macports: libtool arch: libtool gentoo: sys-devel/libtool freebsd: libtool ros-rosdep-0.11.4/test/tree/ros/rospack_fake/000077500000000000000000000000001260171354700210515ustar00rootroot00000000000000ros-rosdep-0.11.4/test/tree/ros/rospack_fake/manifest.xml000066400000000000000000000004011260171354700233740ustar00rootroot00000000000000 rospack Ken Conley BSD http://ros.org/wiki/rospack ros-rosdep-0.11.4/test/tree/ros/stack.xml000066400000000000000000000003211260171354700202440ustar00rootroot00000000000000 ros Maintained by Ken Conley http://ros.org/wiki/ros ros-rosdep-0.11.4/test/tree/stacks/000077500000000000000000000000001260171354700171065ustar00rootroot00000000000000ros-rosdep-0.11.4/test/tree/stacks/empty/000077500000000000000000000000001260171354700202445ustar00rootroot00000000000000ros-rosdep-0.11.4/test/tree/stacks/empty/empty_package/000077500000000000000000000000001260171354700230555ustar00rootroot00000000000000ros-rosdep-0.11.4/test/tree/stacks/empty/empty_package/manifest.xml000066400000000000000000000003631260171354700254070ustar00rootroot00000000000000 empty_package Ken Conley BSD http://ros.org/wiki/empty_package ros-rosdep-0.11.4/test/tree/stacks/empty/stack.xml000066400000000000000000000003601260171354700220720ustar00rootroot00000000000000 empty Maintained by Ken Conley http://ros.org/wiki/empty ros-rosdep-0.11.4/test/tree/stacks/invalid/000077500000000000000000000000001260171354700205345ustar00rootroot00000000000000ros-rosdep-0.11.4/test/tree/stacks/invalid/rosdep.yaml000066400000000000000000000001311260171354700227070ustar00rootroot00000000000000;lkajsdf ;iaj df; p9v8 uzoxijcv;ljzdj ; a;sdkf a;ldsfk ; : asdflkj a l;ajsdf : asdf ros-rosdep-0.11.4/test/tree/stacks/invalid/stack.xml000066400000000000000000000003721260171354700223650ustar00rootroot00000000000000 invalid Maintained by Kenneth Conley http://ros.org/wiki/invalid ros-rosdep-0.11.4/test/tree/stacks/just_a_package/000077500000000000000000000000001260171354700220465ustar00rootroot00000000000000ros-rosdep-0.11.4/test/tree/stacks/just_a_package/manifest.xml000066400000000000000000000003661260171354700244030ustar00rootroot00000000000000 just_a_package Ken Conley BSD http://ros.org/wiki/just_a_package ros-rosdep-0.11.4/test/tree/stacks/packageless/000077500000000000000000000000001260171354700213705ustar00rootroot00000000000000ros-rosdep-0.11.4/test/tree/stacks/packageless/stack.xml000066400000000000000000000004021260171354700232130ustar00rootroot00000000000000 packageless Maintained by Ken Conley http://ros.org/wiki/packageless ros-rosdep-0.11.4/test/tree/stacks/stack1/000077500000000000000000000000001260171354700202745ustar00rootroot00000000000000ros-rosdep-0.11.4/test/tree/stacks/stack1/rosdep.yaml000066400000000000000000000004621260171354700224560ustar00rootroot00000000000000stack1_dep1: ubuntu: dep1-ubuntu debian: dep1-debian stack1_dep2: ubuntu: dep2-ubuntu debian: dep2-debian stack1_p1_dep1: ubuntu: p1dep1-ubuntu debian: p1dep1-debian stack1_p1_dep2: ubuntu: p1dep2-ubuntu debian: p1dep2-debian stack1_p2_dep1: ubuntu: p2dep1-ubuntu debian: p2dep1-debian ros-rosdep-0.11.4/test/tree/stacks/stack1/stack.xml000066400000000000000000000003721260171354700221250ustar00rootroot00000000000000 stack1 Maintained by Kenneth Conley BSD http://ros.org/wiki/stack1 ros-rosdep-0.11.4/test/tree/stacks/stack1/stack1_p1/000077500000000000000000000000001260171354700220625ustar00rootroot00000000000000ros-rosdep-0.11.4/test/tree/stacks/stack1/stack1_p1/manifest.xml000066400000000000000000000005231260171354700244120ustar00rootroot00000000000000 stack1_p1 Kenneth Conley BSD http://ros.org/wiki/stack1_p1 ros-rosdep-0.11.4/test/tree/stacks/stack1/stack1_p2/000077500000000000000000000000001260171354700220635ustar00rootroot00000000000000ros-rosdep-0.11.4/test/tree/stacks/stack1/stack1_p2/manifest.xml000066400000000000000000000005611260171354700244150ustar00rootroot00000000000000 stack1_p2 Kenneth Conley BSD http://ros.org/wiki/stack1_p2 ros-rosdep-0.11.4/test/tree/stacks/stack1/stack1_p3/000077500000000000000000000000001260171354700220645ustar00rootroot00000000000000ros-rosdep-0.11.4/test/tree/stacks/stack1/stack1_p3/manifest.xml000066400000000000000000000004141260171354700244130ustar00rootroot00000000000000 stack1_p3 Kenneth Conley BSD http://ros.org/wiki/stack1_p3 ros-rosdep-0.11.4/test/tree/stacks/stackless/000077500000000000000000000000001260171354700211025ustar00rootroot00000000000000ros-rosdep-0.11.4/test/tree/stacks/stackless/manifest.xml000066400000000000000000000003471260171354700234360ustar00rootroot00000000000000 stackless Ken Conley BSD http://ros.org/wiki/stackless ros-rosdep-0.11.4/test/tree/stacks/twin1/000077500000000000000000000000001260171354700201505ustar00rootroot00000000000000ros-rosdep-0.11.4/test/tree/stacks/twin1/manifest.xml000066400000000000000000000004001260171354700224720ustar00rootroot00000000000000 twin1_pkg Ken Conley BSD http://ros.org/wiki/twin1_pkg ros-rosdep-0.11.4/test/tree/stacks/twin1/rosdep.yaml000066400000000000000000000000531260171354700223260ustar00rootroot00000000000000twin: ubuntu: apt: twin1-value ros-rosdep-0.11.4/test/tree/stacks/twin1/stack.xml000066400000000000000000000003701260171354700217770ustar00rootroot00000000000000 twin1 Maintained by Kenneth Conley BSD http://ros.org/wiki/stack1 ros-rosdep-0.11.4/test/tree/stacks/twin2/000077500000000000000000000000001260171354700201515ustar00rootroot00000000000000ros-rosdep-0.11.4/test/tree/stacks/twin2/manifest.xml000066400000000000000000000004001260171354700224730ustar00rootroot00000000000000 twin1_pkg Ken Conley BSD http://ros.org/wiki/twin1_pkg ros-rosdep-0.11.4/test/tree/stacks/twin2/rosdep.yaml000066400000000000000000000000531260171354700223270ustar00rootroot00000000000000twin: ubuntu: apt: twin2-value ros-rosdep-0.11.4/test/tree/stacks/twin2/stack.xml000066400000000000000000000003701260171354700220000ustar00rootroot00000000000000 twin2 Maintained by Kenneth Conley BSD http://ros.org/wiki/stack1