pax_global_header00006660000000000000000000000064127206731500014515gustar00rootroot0000000000000052 comment=6e85b564d7d59ecdffc1d2e9e6b595952ffde75b rosinstall-0.7.8/000077500000000000000000000000001272067315000137235ustar00rootroot00000000000000rosinstall-0.7.8/.gitignore000066400000000000000000000002071272067315000157120ustar00rootroot00000000000000*.orig *.swp *.pyc *.DS_Store *~ *.log src/rosinstall.egg-info/* build/* deb_dist dist/* .coverage *.deb *.tgz doc-pak description-pak rosinstall-0.7.8/.travis.yml000066400000000000000000000016041272067315000160350ustar00rootroot00000000000000language: python python: - "2.6" - "2.7" - "3.2" - "3.3" - "3.4" # command to install dependencies install: # develop seems to be required by travis since 02/2013 - python setup.py build develop - sudo apt-get clean - sudo apt-get update && sudo apt-get install -qq zsh - sudo pip install vcstools nose-cov coverage PyYAML # Set git config to silence some stuff in the tests - git config --global user.email "foo@example.com" - git config --global user.name "Foo Bar" # Set the hg user - echo -e "[ui]\nusername = Your Name " >> ~/.hgrc # Set the bzr user - bzr whoami "Your Name " # command to run tests script: - python -c 'import sys; print(sys.path)' # Local tests work even if ros.org is down - export ROSINSTALL_SKIP_PYTHON3=1 # - nosetests test/local - nosetests test notifications: email: false matrix: allow_failures: [] rosinstall-0.7.8/LICENSE000066400000000000000000000031051272067315000147270ustar00rootroot00000000000000# Software License Agreement (BSD License) # # 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 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. rosinstall-0.7.8/Makefile000066400000000000000000000011031272067315000153560ustar00rootroot00000000000000.PHONY: all setup clean_dist distro clean install testsetup test NAME='rosinstall' VERSION=$(shell grep version ./src/rosinstall/__version__.py | sed 's,version = ,,') OUTPUT_DIR=deb_dist all: echo "noop for debbuild" setup: echo "building version ${VERSION}" clean_dist: -rm -rf src/rosinstall.egg-info -rm -rf dist -rm -rf deb_dist distro: setup clean_dist python setup.py sdist clean: clean_dist install: distro sudo checkinstall python setup.py install testsetup: echo "running tests" test: testsetup nosetests --with-coverage --cover-package=rosinstall rosinstall-0.7.8/README.rst000066400000000000000000000030701272067315000154120ustar00rootroot00000000000000rosinstall ========== Command-line tools for maintaining a workspace of projects from multiple version-control systems, tailored for the ROS (Robot operating system) community. See http://docs.ros.org/independent/api/rosinstall/html Installing ---------- Install the latest release on Ubuntu using apt-get:: $ sudo apt-get install rosinstall On other Systems, use the pypi package:: $ pip install rosinstall For Bash/Zsh completion:: $ pip install rosinstall-shellcompletion To test in a development environment Developer Environment --------------------- If you want to make changes to vcstools as well, you need to run make to get the vcstools project imported into the devel tree. Source the setup.sh to include the src folder in your PYTHONPATH. Testing ------- Use the python library nose to test:: $ nosetests To test with coverage, make sure to have python-coverage installed and run:: $ nosetests --with-coverage --cover-package vcstools To run python3 compatibility tests, you'd need python-dateutil for python3. Best to create a virtualenv for python3 and pip install python-dateutil to that one. Then:: $ python -m unittest discover --pattern *.py Releasing --------- To test on your local machine you can call make install, with checkinstall installed such that it will make a local deb you can then easily remove. To release make sure that the version number in src/rosinstall/__version__.py and that the doc/changelog.rst are updated. * To upload to pypi make push * To upload to ppa make upload * You will need stdeb available from pip, and rosinstall-0.7.8/doc/000077500000000000000000000000001272067315000144705ustar00rootroot00000000000000rosinstall-0.7.8/doc/Makefile000066400000000000000000000113421272067315000161310ustar00rootroot00000000000000# 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/rosinstall.qhcp" @echo "To view the help file:" @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/rosinstall.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/rosinstall" @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/rosinstall" @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/rosinstall rosinstall-0.7.8/doc/changelog.rst000066400000000000000000000142031272067315000171510ustar00rootroot00000000000000Changelog ========= 0.7.7 ----- - Declared foreach and scrape commands used via wstools as library. 0.7.6 ----- - Fixup documentation. - Put versioned dependencies in for improved output to work. 0.7.5 ----- - Fixed failing tests, likely due to changes in Travis-CI. - Add conflicts for python3 and python2 versions of the rosinstall debians. 0.7.4 ----- - Release to update configurations for newer ubuntu platforms. 0.6 --- 0.6.28 ------ - Rerelease without python 2.7 requirement in debs for lucid 0.6.27 ------ - Upgraded to use the new rosdistro library (REP 137 compliant) 0.6.26 ------ - improved error messages - fixed help text referring to rosws when using wstool - fix #73 roslocate and rosco regressions - enable urlopen using netrc #71 0.6.25 ------ - fix #59: Invalid ROS_PACKAGE_PATH when chaining rosws generated workspaces via setup-file elements - fix regression breaking wstool set command - fix rosws regenrate missing -t option - add --untracked option to rosws info 0.6.24 ------ - fix #55 None split when chaining workspaces via setup-file - now setup.sh returns error code when parsin .rosinstall fails 0.6.23 ------ - fix #47 and #48 rosinstall --generate-versioned-output - fix wstool #4, deletion of symlinked folders - fix rosco bugs #39 and #40 to work with new indexer - better error message when vcstools has wrong version - fix duplicate ROS_PACKAGE_PATH entries from setup-files in fuerte 0.6.22 ------ - missing newline on error output - fix bug around -t option parsing - fix #27 missing import of sys - fix ROS_PACKAGE_PATH set by referenced setup-file overwritten 0.6.21 ------ - unit tests fixed for other ubuntu releases - py3k code (verified with unit-tests on travis-ci) - fix #20 docs - rosbrowse prototype (replaces roslocate) - fix #22 some issues with comparing paths - many code style issues fixed - refactoring of the CLI code - setup.sh creation simplified 0.6.20 ------ - #6 instructions after init give misleading source command with relative path - moved to github, new issue counter - #68 common vcs command shortcuts up, st, rm and di - unit tests run under python3 - bugfix #65 string_diff bug - bugfix #63 broken import of vcstools version caused by missing import - #10 Patch for detecting ROS_ROOT 0.6.19 ------ - Fixing dependencies for release 0.6.18 ------ - fixed some minor bugs around subfolders containing files named .rosinstall - python3 compatibility improved (might still be buggy) - code base cleaned with pychecker and friends - minor improvements to text output - fix #47 support for launchpad urls, no more conflict on update - fix broken scripts rosco, py-rosws-stacks - bugfix #56 setup.sh broken for python3 systems (arch linux) - bugfix #55 rosws and rosinstall, diff and status 0.6.17 ------ - improved generated file code - workaround for #55 (rosinstall only), missing newlines after diff and status (hg and svn) 0.6.16 ------ - #42 implemented rosinstall --verbose and rosws update --verbose to show what files have changed 0.6.15 ------ - bugfix infinite loop possible on race condition 0.6.14 ------ - minor bugfix for #41, setupfiles not regenerated causing rosbash missing on pre-fuerte - changes to docstrings and some messages 0.6.13 ------ - minor bugfixes for #34, #35 0.6.12 ------ - fixed #33 sed -s blunder 0.6.11 ------ - bugfix rosinstall --snapshot not working (refactoring victim) - minor bugfixes on options of rosws update - pyyaml added as dependency in setup.py, rather than failure on import 0.6.10 ------ - undoing bash completion install as it fails with easy_install 0.6.9 ----- - fix #25 rejection of git short-hand notation user@server:file - Create a .rosinstall.bak on every rewrite - diverse minor bugs - strictly accept only one ros root in workspace - parallelity is non-default for init and update, options -j and --parallel like cmake - setup.sh also infers ROS_ROOT from .rosinstall - docs contain tutorial for rosws - more verbose out of paralelity - added this changelog - more versatile info command --only option - bugfix unable to add plain folder - allow to set version to None 0.6.8 ----- - REP110 implemented as rosws, not py-rosws - Restructured rosws command, removed rosws install - improved information given with merge - merge reads from stdin 0.6.7 ----- (does not exist) 0.6.6 ----- - using thread pool - Bugfix busy waiting bug - bugfix sourcing setup.bash leading to build server failure 0.6.5 (unstable) ---------------- - undo deployment of contrib/rosws.shell, did not work 0.6.4 (defective) ----------------- - deployment of contrib/rosws.shell - better exception handling - better debug output - dropped rosws dependency to ROS 0.6.3 (unstable) ---------------- - adapted to vcstools change - major bugfix ROS_PACKGAE_PATH only consisted of relative paths. 0.6.2 (unstable) ---------------- - stricter validation, no non-scm entries within scm entries - minor issues around rosbash 0.6.1 (unstable) ---------------- - bugfix tar not supported - bugfix inofficial 'meta' attribute causes failure 0.6.0 (unstable) ---------------- - new py-rosws CLI as reference implementation for REP110 - parallel operations diff, stat, install - Generally stricter semantics and checking for validity of inputs - No more recursing into other .rosinstall files - roughly 100 more unit tests - refactored single rosinstall script into several python module - setup.sh parses .rosinstall to generate ROS_PACKAGE_PATH 0.5 --- 0.5.30 ------ - small bugfix location-find with rospack - small bugfix roszsh not found - support top-level setup-file element for fuerte 0.5.29 ------ - removed dependency to datetime again 0.5.28 ------ - add allegedly missing dependency to dateutil 0.5.27 ------ - split up integration tests and testing against local repos - support for fuerte setup-file element 0.5.26 ------ - initial support of the preliminary opt/ros/fuerte/.rosinstall file 0.5.25 ------ - fix rosbash for fuerte 0.5.24 ------ - Fixed string defect 0.5.23 (defective) ------------------ - basic catkin support - option -n to not build ros - fix rstripping of ``/`` in uri 0.5.22 ------ - fix #3683 - basic Sphinx support - other fixes 0.5.21 ------ - Moved to kforge rosinstall-0.7.8/doc/conf.py000066400000000000000000000166601272067315000160000ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # rosinstall documentation build configuration file, created by # sphinx-quickstart on Thu Sep 15 16:30:28 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 import os import imp file = None try: file, pathname, description = imp.find_module('__version__', ['../src/rosinstall']) vermod = imp.load_module('__version__', file, pathname, description) version = vermod.version finally: if file is not None: file.close() # 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('../src')) # -- 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.intersphinx', 'sphinx.ext.coverage'] # 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 = 'index' # General information about the project. project = u'rosinstall' 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 = 'haiku' # 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 = {} # 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 = 'rosinstalldoc' # -- 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 = [ ('index', 'rosinstall.tex', u'rosinstall Documentation', u'Tully Foote, Thibault Kruse, Ken Conley, Brian Gerkey', '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/rosinstall', 'rosinstall', u'rosinstall command', [u'Tully Foote, Thibault Kruse, Morgan Quigley, Ken Conley, Brian Gerkey'], 1) ] # Example configuration for intersphinx: refer to the Python standard library. intersphinx_mapping = {'http://docs.python.org/': None} rosinstall-0.7.8/doc/developers_guide.rst000066400000000000000000000050731272067315000205540ustar00rootroot00000000000000Developer's Guide ================= Changelog --------- .. toctree:: :maxdepth: 1 changelog Bug reports and feature requests -------------------------------- - `Submit a bug report `_ Developer Setup --------------- The rosinstall source can be downloaded using Mercurial:: $ git clone https://github.com/vcstools/rosinstall.git You will also need vcstools, which you can either install using pip or download using:: $ git clone https://github.com/vcstools/vcstools.git $ cd vcstools $ python develop To work on the bash completion, there is a separate repository:: $ git clone https://github.com/vcstools/rosinstall_tab_completion.git That one does not contain python code. rosinstall uses `setuptools `_, which you will need to download and install in order to run the packaging. We use setuptools instead of distutils in order to be able use ``setup()`` keys like ``install_requires``. Configure your environment: $ cd rosinstall $ python develop Testing ------- Install test dependencies :: $ pip install nose $ pip install mock rosinstall uses `Python nose `_ for testing, which is a fairly simple and straightforward test framework. The rosinstall mainly use :mod:`unittest` to construct test fixtures, but with nose you can also just write a function that starts with the name ``test`` and use normal ``assert`` statements. rosinstall also uses `mock `_ to create mocks for testing. You can run the tests, including coverage, as follows: :: $ cd rosinstall $ make test Documentation ------------- Sphinx is used to provide API documentation for rosinstall. The documents are stored in the ``doc`` sub-directory. You can build the docs as follows: :: $ cd rosinstall/doc $ make html .. _inofficial-format: Inofficial file format ---------------------- The willow garage build system relies on these two extensions to the rosinstall file format. Basic element types include 'tar', and meta properties can be attached. Example:: - svn: local-name: rosorg meta: repo-name: ros-docs uri: https://code.ros.org/svn/ros/stacks/rosorg/trunk - tar: local-name: foo.tar.bvz2 version: foo-1.2.0 The meta element has no further semantics to rosinstall, it is just passed through. The tar element is an unsupported but required feature of vcstools, with the peculiar semantics that 'version' must refer to a folder inside the tar root. rosinstall-0.7.8/doc/index.rst000066400000000000000000000044641272067315000163410ustar00rootroot00000000000000ROS installation tools ====================== .. module:: rosinstall .. moduleauthor:: Tully Foote , Thibault Kruse , Ken Conley Using rosinstall you can update several folders using a variety of SCMs (SVN, Mercurial, git, Bazaar) with just one command. That way you can more effectively manage source code workspaces. The rosinstall package provides a Python API for interacting with a source code workspace as well as a group of command line tools. Rosinstall leverages the :mod:`vcstools` package for source control and stores its state in .rosinstall files. rosinstall was developed to help with the ROS software, but it has no install dependencies to ROS. It offers support for ROS environments and thus makes some assumptions about ROS being present at runtime, but those can be easily removed and rosws provides all services even when there is no ROS installed. The vision is for the bulk of rosinstall to be a ROS agnostic tool one day. Command Line Tools: =================== .. toctree:: :maxdepth: 2 rosinstall_usage rosws roslocate rosco Installation ============ Ubuntu ------ On Ubuntu the recommended way to install rosinstall is to use apt. If the ros sources are added to your apt sources . To set ROS sources see http://www.ros.org/wiki/fuerte/Installation/Sources :: sudo apt-get install python-rosinstall Other Platforms --------------- On other platforms rosinstall is available on pypi and can be installed via ``pip`` :: pip install -U rosinstall or ``easy_install``: :: easy_install -U rosinstall vcstools Linux and Bash users will benefit a lot from also installing bash completion. This is provided in a different package due to the installation process currently requiring linux. It is only available via pip for now:: pip install -U rosinstall_shellcompletion Tutorials ========= .. toctree:: :maxdepth: 2 rosws_tutorial rosws_ros_tutorial Rosinstall File Format: ======================= .. toctree:: :maxdepth: 2 rosinstall_file_format Advanced: rosinstall developers/contributors ============================================ .. toctree:: :maxdepth: 2 developers_guide Indices and tables ================== * :ref:`genindex` * :ref:`modindex` * :ref:`search` rosinstall-0.7.8/doc/make.bat000066400000000000000000000106471272067315000161050ustar00rootroot00000000000000@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\rosinstall.qhcp echo.To view the help file: echo.^> assistant -collectionFile %BUILDDIR%\qthelp\rosinstall.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 rosinstall-0.7.8/doc/man/000077500000000000000000000000001272067315000152435ustar00rootroot00000000000000rosinstall-0.7.8/doc/man/rosinstall.rst000066400000000000000000000027361272067315000201770ustar00rootroot00000000000000:orphan: rosdep manual page ================== Synopsis -------- **rosinstall** [*options*] <*install-path*> [*rosinstall files or directories*]... Options ------- **--version** Show program's version number and exit **-h**, **--help** Show this help message and exit **-n, --nobuild** Skip the build step for the ROS stack **--rosdep-yes** Pass through --rosdep-yes to rosmake **--continue-on-error** Continue despite checkout errors **--delete-changed-uris** Delete the local copy of a directory before changing URI. **--abort-changed-uris** Abort if changed uri detected **--backup-changed-uris=BACKUP_CHANGED** Backup the local copy of a directory before changing URI to this directory. **--generate-versioned-rosinstall=GENERATE_VERSIONED** Generate a versioned rosinstall file Description ----------- The **rosinstall** command can download source code trees from a variety of source control systems (e.g. Git, Mercurial, Bazaar, Subversion). The rosinstall file format lets you specify multiple source code trees, which simplifies the process of creating development workspaces. rosinstall does the following: 1. Merges all URIs into new or existing .rosinstall file at PATH 2. Checks out or updates all version controlled URIs 3. Calls rosmake after checkout or updates 4. Generates/overwrites updated setup files Run "rosinstall -h" to access the built-in tool documentation. See http://www.ros.org/wiki/rosinstall for more details rosinstall-0.7.8/doc/rosco.rst000066400000000000000000000054051272067315000163530ustar00rootroot00000000000000rosco: checkout source code for ROS resources ============================================= ``rosco`` is instead motivated by "give me the source, now." In exchange for this haste, it does not do any bookkeeping or environment configuration for you: it is tries to be equivalent to running ``svn co``, ``git clone``, or the like. ``rosinstall`` is a useful tool for managing a consistent development tree of multiple ROS stacks. It takes care of important environment configuration, tree updates, and more. It is less useful in situations where you just want to quickly get the source for a particular stack or package as it does more than just retrieve code. For example, you want to add a stack to an existing checkout, you may have to: 1. Lookup the rosinstall entry for the package/stack using ``roslocate``. 2. Update your rosinstall configuration with this information. 3. Run rosinstall, which will iterate through all entries in the rosinstall configuration. If you have multiple entries in the rosinstall configuration, you will have to wait as rosinstall examines each entry for updates. The roslocate script was suggested in [REP115]_. Usage ----- The ``rosco`` command is roughly equivalent to running the equivalent ``svn``, ``git``, or other source control tool to "checkout" or "clone" a repository. It does not record any additional state. rosco '''''''''''''''''''''''' Searches for the specified ROS package or stack and retrieves the source code use the appropriate version control tool. For example, if the source code is stored in a Subversion repository, ``rosco`` will run a ``svn checkout`` of the resource in the local directory. rosco --rosinstall , rosco -r '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' For each entry in the rosinstall file, retrieve the source code use the appropriate version control tool. Unlike ``rosinstall``, it only retrieves the source code and nothing more. piped input ''''''''''' ``rosco`` also accepts piped input formatted as rosinstall entries. This is primarily meant to be used in combination with ``roslocate``. Example:: $ roslocate info rospy | rosco --distro=DISTRO_NAME '''''''''''''''''''' Checkout the source code for a particular ROS distribution release, e.g. ``rosco rospy --distro=electric`` will checkout the Electric release of rospy. This option is not valid when used with ``--rosinstall``. --dev ''''' The ``--dev`` option causes ``rosco`` to checkout the development branch instead. It should be specified in combination with a ``--distro=DISTRO_NAME`` option as development branches are distribution specific. See also -------- .. [REP115] rosco and roslocate tools for rosinstall (http://www.ros.org/reps/rep-0115.html) rosinstall-0.7.8/doc/rosinstall.rst000066400000000000000000000012241272067315000174130ustar00rootroot00000000000000rosinstall Package ================== .. contents:: Contents :depth: 2 :mod:`rosinstall` Package ------------------------- The rosinstall package currently contains all modules of rosinstall and rosws. The `*_cmd` modules provide general services to query or modify the model. They should keep printing and command line assumptions to a minimum, optimally functions in here should be callable from any UI. The `*_cli` modules implement actual command line interface tools, and thus provide command line argument parsing and pretty printing. Optimally functions in here do not contain any algorithmic code that can be useful for more than one UI. rosinstall-0.7.8/doc/rosinstall_file_format.rst000066400000000000000000000040201272067315000217570ustar00rootroot00000000000000rosinstall file format ====================== REP 126 ------- The rosinstall file format was changed in [REP126]_. Format ------ The rosinstall file format is a yaml document. It is a list of top level dictionaries. Each top level dictionary is expected to have one of the vcs type keys and no other keys. Inside every top level dictionary there is one required key, ``local-name`` this represents the path where to install files. It will support both workspace relative paths as well as absolute paths. Each of the vcs type keys requires a ``uri`` key, and optionally takes a ``version`` key. Additional experimental keys exist, which may be changed or go out of support anygiventime: :ref:`inofficial-format`. Top Level Keys -------------- The valid keys are ``svn``, ``hg``, ``git``, ``bzr``, ``other``, ``setup-file``. Each key represents a form of version control system to use. These are supported from the vcstools module. The ``other`` key is used to add a path to the workspace without associating a version control system. In [REP126]_ the key ``setup-file`` was added to support the Fuerte release. Example rosinstall syntax: -------------------------- Below is an example rosinstall syntax with examples of most of the possible permutations: :: - svn: {local-name: some/local/path2, uri: /some/local/uri} - hg: {local-name: some/local/path3, uri: http://some/uri, version: 123} - git: {local-name: /some/local/aboslute/path, uri: http://some/uri, version: 123} - bzr: {local-name: some/local/path4, uri: http://some/uri, version: 123} - setup-file: local-name: /opt/ros/fuerte/setup.sh - other: local-name: /opt/ros/fuerte/share/ros Things to note are: - VCS keys require ``uri``, but ``version`` is optional though recommended. - Absolute or relative paths are valid for ``local-name`` - ``setup-file`` and ``other`` do not take any keys besides ``local-name`` - ``uri`` can be a local file path to a repository. See also -------- .. [REP126] setup-file root element (http://www.ros.org/reps/rep-0126.html) rosinstall-0.7.8/doc/rosinstall_usage.rst000066400000000000000000000133101272067315000205760ustar00rootroot00000000000000rosinstall: source-based install tool ===================================== Usage ----- :: Usage: rosinstall [options] Options: --version show program's version number and exit -h, --help show this help message and exit -c, --catkin Declare this is a catkin build. --cmake-prefix-path=CATKINPP Where to set the CMAKE_PREFIX_PATH, implies --catkin --version display version information --verbose display more information -n, --nobuild skip the build step for the ROS stack --rosdep-yes Pass through --rosdep-yes to rosmake --delete-changed-uris Delete the local copy of a directory before changing uri. --abort-changed-uris Abort if changed uri detected --backup-changed-uris=BACKUP_CHANGED backup the local copy of a directory before changing uri to this directory. --diff shows a combined diff over all SCM entries --status shows a combined status command over all SCM entries --status-untracked shows a combined status command over all SCM entries, also showing untracked files -j JOBS, --parallel=JOBS How many parallel threads to use for installing --generate-versioned-rosinstall=GENERATE_VERSIONED generate a versioned rosintall file The first `` is the filesystem path where the source code will be downloaded. Any additional `` are treated as locations from which to fetch additional rosinstall file configuration. *These can be filesystem paths or URLs*. The behavior of rosinstall depends on what `` points to: - If an additional path is a filesystem directory, rosinstall will look for a `.rosinstall` file in the directory, and then overlay the new environment on top of that directory's configuration. - If an additional path points to a `.rosinstall` file, rosinstall will include the contents of that file. For example:: rosinstall ~/ros "http://packages.ros.org/cgi-bin/gen_rosinstall.py?rosdistro=electric&variant=desktop-full&overlay=no" After installation, ``rosinstall`` writes a bash setup file, called ``setup.bash``, into ````. Source this file to configure your `environment variables`_. .. _environment variables: http://ros.org/wiki/ROS/EnvironmentVariables rosinstall will also store the checkout information used in ``/.rosinstall``. Updating a rosinstall checkout ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ After using rosinstall to download and setup a certain directory tree. You can update the the contents of that tree using rosinstall as well. :: rosinstall ~/workspace will read the ``.rosinstall`` file in ``~/ros`` and then call ``svn up`` or other VCS "update" equivalent. This will also regenerate the ``setup.bash`` environment file. If you are already in ``~/workspace`` you can update by typing:: rosinstall . Examples usages ~~~~~~~~~~~~~~~ *Developing on top of boxturtle shared install*:: rosinstall ~/workspace /opt/ros/boxturtle http://www.ros.org/rosinstalls/wg_boxturtle_devel.rosinstall *Full source checkout*:: rosinstall ~/workspace http://www.ros.org/rosinstalls/boxturtle_pr2all.rosinstall *Developing a stack against a full tree*:: rosinstall ~/workspace http://www.ros.org/rosinstalls/boxturtle_pr2all.rosinstall my_stack.rosinstall *Adding a rosinstall layout to an existing workspace* Create a new workspace directory and include `/opt/ros/diamondback` in the `ROS_PACKAGE_PATH`:: rosinstall ~/workspace /opt/ros/diamondback Add wg_boxturtle_devel packages to the workspace:: rosinstall ~/workspace http://www.ros.org/rosinstalls/wg_boxturtle_devel.rosinstall Rosinstall Under the Hood ------------------------- This is a summary of how rosinstall works under the hood. Process Flow ~~~~~~~~~~~~ Whenever rosinstall is executed the following code path is followed: #. Gather command line arguments #. Merge source rosinstall files #. Install source #. Generate a setup file. Merging source rosinstall files ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 1. Rosinstall will start with the `.rosinstall` file in the install path. * If one doesn't exist it will create an empty one. 2. To this it will append the contents of all arguments in order left to right. * if the argument is a directory it will look for a `DIRECTORY/.rosinstall` and add all elements as `other` elements with `local-name` set to the full path. * if the argument is a url or a path to a file it will directly take the contents 3. Duplicates will be removed based on the key 'local-name'. The later definition will be preserved. 4. This `.rosinstall` file will be saved to disk. Installing Source ~~~~~~~~~~~~~~~~~ #. rosinstall will iterate through the `.rosinstall` file for each definition of source. #. If the source directory does not exist it will be created and checked out #. if the source directory exists and is of the same `uri` it will be updated #. If the source directory exists and the uri doesn't match the user will be prompted to abort, delete, or backup Generating setup.bash ~~~~~~~~~~~~~~~~~~~~~ 1. After a successful installation `rosinstall` will iterate through each of the elements in `.rosinstall` and add their `local-name` to the ROS_PACKAGE_PATH, unless the path is detected to be ros, in which case it will be set to ROS_ROOT. * This will error if a ROS directory is not detected. (The ros directory must be explicitly called out in the `local-name`) 2. The setup file will be written to disk. rosinstall-0.7.8/doc/roslocate.rst000066400000000000000000000115231272067315000172170ustar00rootroot00000000000000roslocate: locate source-control repositories ============================================= ``roslocate`` is a tool for finding version-control and other information about a ROS package or stack. The main use is to locate the source-control repository of a resource, though it can also provide additional metadata about that resource. The roslocate script was suggested in [REP115]_. .. contents:: :depth: 3 Usage ----- :: roslocate info Get rosinstall info of resource vcs Get name of source control system type Package or stack uri Get source control URI of resource www Get web page of resource repo Get repository name of resource describe Get description of resource ``roslocate`` has a command-based API. Each of the commands is described below. describe '''''''' ``roslocate describe`` summarizes information about a ROS package or stack. Example:: $ roslocate describe rosinstall Type: package Stack: ros_release Description: rosinstall is a tool to check out ROS source code (or any source code, really) from multiple version control repositories and updating these checkouts. Given a *.rosinstall file that specifies where to get code, rosinstall will check out a working copy for you. We recommend the use of rosinstall when checking out development versions of ROS source code. This package is where the code lives, however it is not expected for users to checkout and use this package directly. It is expected that users use the version available through pypi.python.org. URL: http://ros.org/wiki/rosinstall info '''' Prints the rosinstall entry for the resource. Example:: $ roslocate info common - hg: local-name: common meta: repo-name: wg-kforge uri: https://kforge.ros.org/common/common version: default repo '''' Prints the name of the repository the resource is stored in. This repository name is for display purposes only -- it cannot be used as input to source control tools. Example:: $ roslocate repo cram_pl tum-ros-pkg uri ''' Prints the source control URI of a resource. This is mainly intended as input to other programs via shell backtick or pipe. Example:: $ roslocate uri rospy https://code.ros.org/svn/ros/stacks/ros_comm/trunk/clients/rospy vcs ''' Prints the type of version control system used for the resource. Possible values include ``svn``, ``hg``, ``git``, and ``bzr``. Example:: $ roslocate vcs common hg www ''' Prints the website of a resource. Example:: $ roslocate www rospy http://ros.org/wiki/rospy --distro=DISTRO_NAME '''''''''''''''''''' If the ``--distro=DISTRO_NAME`` option is combined with a roslocate command, the information returned will be based on a particular distribution release of a resource. Example:: $ roslocate info rospy - svn: local-name: rospy uri: https://code.ros.org/svn/ros/stacks/ros_comm/trunk/clients/rospy $ roslocate info rospy --distro=diamondback - svn: local-name: ros_comm uri: https://code.ros.org/svn/ros/stacks/ros_comm/tags/ros_comm-1.4.7 --dev ''''' If the ``--dev`` option is combined with a roslocate command, the information returned will be based on the development branch of the resource (e.g. ``trunk``), if possible. It should be used in combination with the ``--distro=DISTRO_NAME`` option as development trees are indexed based on a particular ROS distribution. The ``-dev`` option generally only affects source control information, like URIs and rosinstall entries. Other information, like resource descriptions, are not guaranteed to be development-branch specific. Example:: $ roslocate info rospy --distro=electric - svn: local-name: ros_comm uri: https://code.ros.org/svn/ros/stacks/ros_comm/tags/ros_comm-1.6.0 $ roslocate info rospy --distro=electric --dev - svn: local-name: ros_comm uri: https://code.ros.org/svn/ros/stacks/ros_comm/trunk Indexer ------- ``roslocate`` is a command-line interface for accessing information produced by the ROS.org indexing system, which crawls the known public repositories of ROS-compatible software. The process for getting a repository added to this index is described `on the "Get Involved" ROS.org page `_. The indexer files themselves are stored in the ``rosdoc_rosorg`` package, which can be `browsed online`_. Of particular interest is the ``repos.list`` file as well as the individual rosinstall file in the ``repos`` directory. .. _browsed online: https://code.ros.org/svn/ros/stacks/rosorg/trunk/rosdoc_rosorg/>_`. See also -------- .. [REP115] rosco and roslocate tools for rosinstall (http://www.ros.org/reps/rep-0115.html) rosinstall-0.7.8/doc/rosws.rst000066400000000000000000000237121272067315000164040ustar00rootroot00000000000000rosws: A tool for managing source code workspaces ================================================= rosws can do anything that rosinstall can do, and more. Most commands will just do a small subset of a single rosinstall invocation, so users can more easily understand and control the tool actions. The main difference to rosinstall is that rosws uses an SCM like syntax of command keywords. The motivation for rosws was that many users were overwhelmed with the number of things rosinstall does with just one command, and ended up not using it at all. rosws does much less and informs the user more about what it will do, so that users should feel safer and also should more easily understand what the tool is doing. The single most important feature that is different to rosinstall is the info command. The second most is the set command. The general design philosophy for rosws wa that each command should just perform a single task, not multiple tasks. The command was introduced with [REP110]_. .. contents:: Contents :depth: 3 Usage ----- :: rosws is a command to manipulate ROS workspaces. rosws replaces its predecessor rosinstall. Official usage: rosws CMD [ARGS] [OPTIONS] rosws will try to infer install path from context Type 'rosws help' for usage. Options: help provide help for commands init set up a directory as workspace set add or changes one entry from your workspace config merge merges your workspace with another config set remove (rm) remove an entry from your workspace config, without deleting files update (up) update or check out some of your config elements info Overview of some entries status (st) print the change status of files in some SCM controlled entries diff (di) print a diff over some SCM controlled entries regenerate create ROS workspace specific setup files init ~~~~ set up a directory as workspace rosws init does the following: 1. Reads folder/file/web-uri SOURCE_PATH looking for a rosinstall yaml 2. Creates new .rosinstall file at TARGET-PATH configured 3. Generates ROS setup files SOURCE_PATH can e.g. be a folder like /opt/ros/electric If PATH is not given, uses current folder. :: Usage: rosws init [TARGET_PATH [SOURCE_PATH]]? Options:: -h, --help show this help message and exit -c, --catkin Declare this is a catkin build. --cmake-prefix-path=CATKINPP Where to set the CMAKE_PREFIX_PATH --continue-on-error Continue despite checkout errors -j JOBS, --parallel=JOBS How many parallel threads to use for installing Examples:: $ rosws init ~/fuerte /opt/ros/fuerte set ~~~ add or changes one entry from your workspace config The command will infer whether you want to add or modify an entry. If you modify, it will only change the details you provide, keeping those you did not provide. if you only provide a uri, will use the basename of it as localname unless such an element already exists. The command only changes the configuration, to checkout or update the element, run rosws update afterwards. :: Usage: rosws set [localname] [SCM-URI]? [--(detached|svn|hg|git|bzr)] [--version=VERSION]] Options: -h, --help show this help message and exit --detached make an entry unmanaged (default for new element) -v VERSION, --version-new=VERSION point SCM to this version --git make an entry a git entry --svn make an entry a subversion entry --hg make an entry a mercurial entry --bzr make an entry a bazaar entry -y, --confirm Do not ask for confirmation -u, --update update repository after set -t WORKSPACE, --target-workspace=WORKSPACE which workspace to use Examples:: $ rosws set robot_model --hg https://kforge.ros.org/robotmodel/robot_model $ rosws set robot_model --version robot_model-1.7.1 $ rosws set robot_model --detached merge ~~~~~ The command merges config with given other rosinstall element sets, from files or web uris. The default workspace will be inferred from context, you can specify one using -t. By default, when an element in an additional URI has the same local-name as an existing element, the existing element will be replaced. In order to ensure the ordering of elements is as provided in the URI, use the option ``--merge-kill-append``. :: Usage: rosws merge [URI] [OPTIONS] Options: -h, --help show this help message and exit -a, --merge-kill-append merge by deleting given entry and appending new one -k, --merge-keep (default) merge by keeping existing entry and discarding new one -r, --merge-replace merge by replacing given entry with new one maintaining ordering -y, --confirm-all do not ask for confirmation unless strictly necessary -t WORKSPACE, --target-workspace=WORKSPACE which workspace to use Examples:: $ rosws merge someother.rosinstall You can use '-' to pipe in input, as an example:: $ roslocate info robot_mode | rosws merge - update ~~~~~~ update or check out some of your config elements This command calls the SCM provider to pull changes from remote to your local filesystem. In case the url has changed, the command will ask whether to delete or backup the folder. :: Usage: rosws update [localname]* Options: -h, --help show this help message and exit --delete-changed-uris Delete the local copy of a directory before changing uri. --abort-changed-uris Abort if changed uri detected --continue-on-error Continue despite checkout errors --backup-changed-uris=BACKUP_CHANGED backup the local copy of a directory before changing uri to this directory. -j JOBS, --parallel=JOBS How many parallel threads to use for installing -v, --verbose Whether to print out more information -t WORKSPACE, --target-workspace=WORKSPACE which workspace to use Examples:: $ rosws update -t ~/fuerte $ rosws update robot_model geometry info ~~~~ Overview of some entries The Status (S) column shows x for missing L for uncommited (local) changes V for difference in version and/or remote URI C for difference in local and remote versions The 'Version-Spec' column shows what tag, branch or revision was given in the .rosinstall file. The 'UID' column shows the unique ID of the current (and specified) version. The 'URI' column shows the configured URL of the repo. If status is V, the difference between what was specified and what is real is shown in the respective column. For SVN entries, the url is split up according to standard layout (trunk/tags/branches). The ROS_PACKAGE_PATH follows the order of the table, earlier entries overlay later entries. When given one localname, just show the data of one element in list form. This also has the generic properties element which is usually empty. The ``--only`` option accepts keywords: ['path', 'localname', 'version', 'revision', 'cur_revision', 'uri', 'cur_uri', 'scmtype'] :: Usage: rosws info [localname]* [OPTIONS] Options: -h, --help show this help message and exit --root Show workspace root path --data-only Does not provide explanations --no-pkg-path Suppress ROS_PACKAGE_PATH. --pkg-path-only Shows only ROS_PACKAGE_PATH separated by ':'. Supercedes all other options. --only=ONLY Shows comma-separated lists of only given comma- separated attribute(s). --yaml Shows only version of single entry. Intended for scripting. --fetch When used, retrieves version information from remote (takes longer). -u, --untracked Also show untracked files as modifications -t WORKSPACE, --target-workspace=WORKSPACE which workspace to use Examples:: $ rosws info -t ~/ros/fuerte $ rosws info robot_model $ rosws info --yaml $ rosws info --only=path,cur_uri,cur_revision robot_model geometry status ~~~~~~ print the change status of files in some SCM controlled entries. The status columns meanings are as the respective SCM defines them. :: Usage: rosws status [localname]* Options: -h, --help show this help message and exit --untracked Also shows untracked files -t WORKSPACE, --target-workspace=WORKSPACE which workspace to use diff ~~~~ print a diff over some SCM controlled entries :: Usage: rosws diff [localname]* Options: -h, --help show this help message and exit --untracked Also shows untracked files -t WORKSPACE, --target-workspace=WORKSPACE which workspace to use regenerate ~~~~~~~~~~ remove an entry from your workspace config, without deleting files this command without options generates files setup.sh, setup.bash and setup.zsh. Note that doing this is unnecessary in general, as these files do not change anymore, unless you change from one ROS distro to another (which you should never do like this, create a separate new workspace instead), or you deleted or modified any of those files accidentally. :: Usage: rosws regenerate Options: -h, --help show this help message and exit -c, --catkin Declare this is a catkin build. --cmake-prefix-path=CATKINPP Where to set the CMAKE_PREFIX_PATH See also -------- .. [REP110] SCM-like rosinstall command structure (http://www.ros.org/reps/rep-0110.html) rosinstall-0.7.8/doc/rosws_ros_tutorial.rst000066400000000000000000000236231272067315000212130ustar00rootroot00000000000000.. _rosws_ros_tutorial: rosws ROS Tutorial ================== In this tutorial we will focus on how to use ``rosws`` for doing development work for ROS. We will use the ROS fuerte distribution, but you can use other distributions as well. .. contents:: Contents :depth: 3 Introduction ------------ The problem ``rosws`` tries to solve is that developers in robotics today have to work with source code from multiple sources, multiple version control systems, in multiple versions. While many ROS libraries can be installed into system directories via Debian packages or other system-based distribution mechanisms, many developers have ROS libraries installed from source somewhere in their home directory, and then made available at runtime by inclusion in the ``ROS_PACKAGE_PATH`` environment variable. By manipulating this environment variable, users can create their own packages, install additional packages from source, or even shadow installed packages with experimental versions. There are a few ways to manage these "overlay" environments. A user can manage ``ROS_PACKAGE_PATH`` environment variable by hand, but this is cumbersome, can lead to confusion when switching environments, and errors in this variable can easily break a user's environment. Alternatively, ``rosws`` (ROS Workspace) provides a systematic method for managing package overlays in a user's workspace. When the developer makes changes to the source code and builds the code, it is important that the builder uses the right ROS distribution (e.g. electric vs fuerte) as well as the right version of the source code. A builder will typically use environment variables such as ``CPATH, LD_LIBRARY_PATH, PKG_CONFIG_PATH,`` etc. So the developer will have to make sure that all those variables are all set correctly every time he runs a build. Similarly, when the developer has a ROS package both installed as a system library as well as local 'overlay' checkout (with his modifications), it is important that the builder chooses the right libraries for the build process, so the order of entries in the environment variables also needs to be managed. This is what ``rosws`` attempts to make easier for developers. Binding a workspace to a ROS distribution ----------------------------------------- The following command creates a new fuerte overlay workspace in ~/fuerte:: $ rosws init ~/fuerte /opt/ros/fuerte .. note:: This command does nothing else than to create the folder ``~/fuerte``, the files ``setup.bash``, ``setup.sh``, ``setup.zsh`` and the hidden file ``.rosinstall`` in the directory ``~/fuerte``. We will use ``~/fuerte`` from now on. Other workspaces could be set up similarly like this:: $ rosws init ~/electric /opt/ros/electric $ rosws init ~/electric_unstable /opt/ros/electric The next step is to source the ``setup.bash`` in ``~/fuerte``:: $ source ~/fuerte/setup.bash .. note:: You can only source one workspace at a time. It is generally error prone to switch from one workspace to another, this can cause confusing errors. Prefer to keep the same workspace in the same terminal. If you work with several workspaces, do not source any of them in your ``.bashrc``. It is very common to replace the line ``source /opt/ros/fuerte/setup.bash`` in the ``.bashrc`` to the command above, so that whenever you create a new terminal, that environment is used. You can verify the workspace using again ``rosws info``:: $ rosws info workspace: ~/fuerte ROS_ROOT: /opt/ros/fuerte/share/ros Localname S SCM Version-Spec UID (Spec) URI (Spec) (https://...) --------- - ---- ------------ ----------- ------------------------- /opt/ros/fuerte/stacks /opt/ros/fuerte/share /opt/ros/fuerte/share/ros You see in the second output line that there is a defined ROS_ROOT in our workspace. The info table has many columns, all of which are empty so far, we will get to that in a moment. You may notice that ``rosws merge`` listed an added setup.sh, which is not shown in the table, it is hidden because that entry is of no further interest to you in your daily work. The overlay now includes all packages that were installed in ``/opt/ros/fuerte``, which is by itself not very useful yet. However we can now easily overlay installed packages. Creating a sandbox directory for new packages --------------------------------------------- New packages need to be put in a path that is in the variable ``ROS_PACKAGE_PATH``. All directories that are managed by ``rosws``, i.e. that have been added using ``rosws`` are automatically added to the ``ROS_PACKAGE_PATH`` when the file ``setup.bash`` of the corresponding workspace is sourced. Although new packages should always be put in repositories that have been installed using ``rosws``, it can be very convenient to have a sandbox directory where for instance packages created during the tutorials can be put without requiring any additional ``rosws`` commands. For that we create a new directory sandbox and add it to the .rosinstall file:: $ mkdir ~/fuerte/sandbox $ rosws set ~/fuerte/sandbox .. note:: Now, it is necessary to re-source ``~/fuerte/setup.bash`` to make sure that the updated ``ROS_PACKAGE_PATH`` is used:: $ source ~/fuerte/setup.bash You can verify the workspace using again ``rosws info``:: $ cd ~/fuerte $ rosws info workspace: ~/fuerte ROS_ROOT: /opt/ros/fuerte/share/ros Localname S SCM Version-Spec UID (Spec) URI (Spec) (https://...) --------- - ---- ------------ ----------- ------------------------- sandbox /opt/ros/fuerte/stacks /opt/ros/fuerte/share /opt/ros/fuerte/share/ros As you can see the sandbox folder is at the top of the list. This is important, as early entries overlay later entries. You can also check the ``ROS_PACKAGE_PATH``, it should be the same as the left column of the table:: $ echo $ROS_PACKAGE_PATH /home/user/fuerte/sandbox:/opt/ros/fuerte/stacks:/opt/ros/fuerte/share:/opt/ros/fuerte/share/ros You can now create packages in the sandbox folder e.g. using ``roscreate-pkg``, and they will be found within the ROS_PACKAGE_PATH. Adding repositories to the overlay ---------------------------------- Development normally happens in repositories and when installing packages from source, they normally need to be checked out from a repository and added to the ``ROS_PACKAGE_PATH``. This can easily be done using ``rosws``. For instance, the following commands add the development version of the stack turtlebot which is a Mercurial repository:: $ rosws set turtlebot --hg https://kforge.ros.org/turtlebot/turtlebot $ rosws update turtlebot After re-sourcing setup.bash the new overlayed stack turtlebot should be in your package path, i.e. ``roscd turtlebot`` should switch to the directory ``~/fuerte/turtlebot``. If a stack is already installed in ``/opt/ros/fuerte``, adding it locally using ``rosws`` will shadow the existing stack, as long as ``rosws`` info lists the stack earlier than the ``/opt/ros/fuerte`` folders. I.e. instead of the system installation, the stack in ``~/ros_workspace`` will be used. That way, it is possible to edit existing packages by cloning them in the overlay. This makes it possible for you to use different workspaces with different versions of the same libraries without much hassle. Also this allows multiple users on a robot to each have their own version of libraries. Combining merge with roslocate ------------------------------ A usecase that was considered in the design of ``rosws`` was to quickly get ROS stacks into a workspace. The ``roslocate`` script uses an online index to lookup stack or package source information by name. We can pipe that information to ``rosws`` to add the definition to our workspace. As an example we will add the navigation stack. Just to show you what is happening, we first call ``roslocate``:: $ roslocate info navigation - hg: local-name: navigation meta: repo-name: wg-kforge uri: https://kforge.ros.org/navigation/navigation version: default As you can see the command finds the required meta-information for a stack or package by the given name ``navigation``. We can call ``roslocate info`` it again passing the output to "``rosws merge -``":: $ roslocate info navigation | rosws merge - Performing actions: Add new elements: navigation hg https://kforge.ros.org/navigation/navigation default If you wanted, you could next checkout the source code calling ``rosws update navigation``. Updating repositories in an overlay ----------------------------------- ``rosws`` allows to update only a single repository or all repositories:: $ rosws update navigation updates only the stack navigation while:: $ rosws update updates all repositories. Developing against multiple distributions ----------------------------------------- As an example a developer might have the ROS navigation stack in versions electric stable, electric unstable and fuerte on his harddisk. (You may not have more than one distribution when you start learning ROS, but the next distribution will come, so it's good to be prepared.) So as a developer, it is be good to create one local overlay workspace for each distribution and variant to use:: $ rosws init ~/fuerte /opt/ros/fuerte $ rosws init ~/electric /opt/ros/electric $ rosws init ~/electric_unstable /opt/ros/electric It is useful to use such folders to manage different source checkouts of the same ROS package. Using the same folder and switching versions is very prone to mistakes and not recommended. You can use each of these folders as an independent workspace. .. note:: It is generally not a good idea to change the distribution a ROS workspace is bound to. This often leads to confusing error messages because compiled files assume the wrong distribution. rosinstall-0.7.8/doc/rosws_tutorial.rst000066400000000000000000000426521272067315000203330ustar00rootroot00000000000000rosws Tutorial ============== In this tutorial we will set up a workspace using different SCM providers and introduce the ``rosws`` commands to run SCM configuration operations in this workspace. In the context of rosws, a workspace is a set of folders on your harddisk that are listed in a special file named ``.rosinstall``. Also this file stores for each folder whether this folder is managed under some version control system (subversion, mercurial, git, bazaar). This allows you to deal with many common version control operations using a single interface. rosws also generates a file called setup.sh. This adds all folders listed in the .rosinstall to an environment variable called ROS_PACKAGE_PATH. This variable can the be used by other tools to e.g. find folders with libraries you want to compile against. In you get stuck with a technical problem, you may check out the answers page: http://answers.ros.org/questions/tags:rosinstall .. contents:: Contents :depth: 3 Prerequisites ------------- Start by updating / installing ``rosws``, which comes with rosinstall. *Ubuntu* On Ubuntu you first need to setup ROS sources: http://www.ros.org/wiki/fuerte/Installation/Sources :: $ sudo apt-get install python-rosinstall If you do not want to add the ROS sources as outlined above you can use ``pip`` as outlined below, but know that ``pip`` won't automatically update and overrides any verison installed from debian packages. *Other Platforms* On platforms where debian packages are You will need the program ``pip`` You can then get the latest rosinstall like this: :: $ sudo pip install -U rosinstall Troubleshoot ~~~~~~~~~~~~ If you had rosinstall series 0.5 installed, you may encounter conflicts like:: ImportError: No module named rosinstall.rosinstall_cli To fix this, you will have to remove leftover directories from the earlier install, as sadly the python setuptools will not do it for you. On Ubuntu Lucid, as an example:: $ sudo rm -rf /usr/local/lib/python2.6/dist-packages/rosinstall-0.5* Initialize a workspace ---------------------- We will create a folder that serves as workspace, which you can delete after the tutorial. .. note:: The following creates a workspace without ROS. This means variables that are important for ROS like ROS_PACKAGE_PATH will not be set. If you want to create a workspace for ROS, follow the tutorial :ref:`rosws_ros_tutorial`. :: $ cd /tmp $ mkdir rosws_tutorial $ cd rosws_tutorial $ rosws init Writing /tmp/rosws_tutorial/.rosinstall (Over-)Writing setup.sh, setup.bash, and setup.zsh in /tmp/rosws_tutorial rosws init complete. Type 'source ./setup.bash' to change into this environment. Add that source command to the bottom of your ~/.bashrc to set it up every time you log in. If you are not using bash please see http://www.ros.org/wiki/rosinstall/NonBashShells To see what this command did, just type: :: $ ls -a ./ ../ .rosinstall setup.bash setup.sh setup.zsh This is all that ``rosws init`` does, it creates these files. If you ever want to start your workspace over, you can delete all these files, and that's it. Note that ``rm *`` on linux does not delete the ``.rosinstall``, you need to call ``rm .rosinstall`` as well. We can run ``rosws info`` to see an overview of the environment: :: $ rosws info workspace: /tmp/rosws_tutorial ROS_ROOT: None As you can see the workspace is empty and we do not have a ros root in the workspace. For this tutorial, we will use the ROS fuerte release. Note though that you do not need a ros root to have a valid workspace with rosws. Now is a good time to check out the ``help`` and ``--version`` commands:: $ rosws help $ rosws help init $ rosws help info $ rosws --version Remember this help is available if you get in trouble. Extending your workspace ------------------------ Using rosws is useful for mostly one purpose, using several SCM repositories, like Subversion, git, Mercurial, Bazaar. So far in our workspace we have none such folders, so let's see how we can add a few. For the sake of having an example, let us try a merge in stacks from the electric ROS distribution. (This will not take long, trust me). You do not need any ros installation for this step of the tutorial. :: $ rosws merge 'http://packages.ros.org/cgi-bin/gen_rosinstall.py?rosdistro=electric&variant=robot&overlay=yes' Performing actions: Add new elements: nodelet_core, xacro, eigen, bond_core, pluginlib, geometry, robot_model, assimp, orocos_kinematics_dynamics, common, filters, diagnostics, bullet, driver_common, executive_smach, common_msgs Overwriting /tmp/rosws/.rosinstall rosws update complete. Do not forget to do ... $ source /tmp/rosws/setup.sh ... in every open terminal. Config changed, remember to run rosws update to update the tree What this command did is just adding entries to your .rosinstall, nothing else so far. The ``rosws`` tool behaves differently from the rosinstall ``tool`` in that respect. We can inspect the new config in detail again using the ``rosws info`` command: :: $ rosws info Localname S SCM Version-Spec UID (Spec) URI (Spec) (https://...) --------- - ---- ------------ ----------- ------------------------- xacro x hg xacro-1.6.0 kforge.ros.org/common/xacro executive_smach x hg executive_smach-1.0.4 kforge.ros.org/smach/executive_smach robot_model x hg robot_model-1.6.4 kforge.ros.org/robotmodel/robot_model assimp x hg assimp-0.1.1 kforge.ros.org/robotmodel/assimp pluginlib x hg pluginlib-1.6.0 kforge.ros.org/common/pluginlib orocos_kinematics_dynamics x git orocos_kinematics_dynamics-0.2.3 http://git.mech.kuleuven.be/robotics/orocos_kinematics_dynamics.git nodelet_core x hg nodelet_core-1.6.2 kforge.ros.org/common/nodeletcore geometry x hg geometry-1.6.1 kforge.ros.org/geometry/geometry bullet x hg bullet-2.76.5 kforge.ros.org/geometry/bullet filters x hg filters-1.6.0 kforge.ros.org/common/filters eigen x hg eigen-1.6.0 kforge.ros.org/geometry/eigen driver_common x svn tags/driver_common-1.2.4 code.ros.org/svn/ros-pkg/stacks/driver_common/ diagnostics x svn tags/diagnostics-1.6.4 code.ros.org/svn/ros-pkg/stacks/diagnostics/ common x hg common-1.6.1 kforge.ros.org/common/common common_msgs x svn tags/common_msgs-1.6.0 code.ros.org/svn/ros-pkg/stacks/common_msgs/ bond_core x hg bond_core-1.6.1 kforge.ros.org/common/bondcore /opt/ros/fuerte/stacks /opt/ros/fuerte/share /opt/ros/fuerte/share/ros So this looks much more fun. For each stack definition that we merged in, we see the SCM provider, the URI, and the version. The column labeled ``S`` gives us the status, an ``x`` means that the folder is missing. That's because we did only merge in the definitions, so far we did not pull the actual stacks. The ``UID (Spec)`` column would show the current revision of each stack, but as we did not check out any, it is empty for all. .. note:: For svn, rosws, uses the standard layout to reduce table width. So uri = ``https://code.ros.org/svn/ros-pkg/stacks/common_msgs/tags/common_msgs-1.6.0`` becomes uri = ``code.ros.org/svn/ros-pkg/stacks/common_msgs`` Version-Spec = ``tags/common_msgs-1.6.0`` We can use ``rosws info`` also to compare just a few entries and to look into one entry in detail: :: $ rosws info common filters Localname S SCM Version-Spec UID (Spec) URI (Spec) (https://...) --------- - ---- ------------ ----------- ------------------------- filters x hg filters-1.6.0 kforge.ros.org/common/filters common x hg common-1.6.1 kforge.ros.org/common/common $ rosws info diagnostics Localname: diagnostics Path /tmp/rosws_tutorial/diagnostics Status: x SCM: svn URI: https://code.ros.org/svn/ros-pkg/stacks/diagnostics/tags/diagnostics-1.6.4 Current URI: Version-Spec: Spec-Revision: Current-Revision: Other Properties: [] As you can see, the display changes if we just give one entry, and the SVN uri is displayed in the original format stored in the ``.rosinstall`` file. Since we do not want to strain your network connection, we will undo the merge. rosws created a ``.rosinstall.bak`` file when we run the merge command. You can always undo one change by replacing ``.rosinstall`` with the ``.rosinstall.bak``. :: $ mv .rosinstall.bak .rosinstall Working with Entries -------------------- To have something small to work with, we will add single ROS stack to our workspace for real. The ``set`` command is for manual adding of entries: :: $ rosws set common_msgs https://code.ros.org/svn/ros-pkg/stacks/common_msgs/trunk --svn Add element: {'svn': {'local-name': 'common_msgs', 'uri': 'https://code.ros.org/svn/ros-pkg/stacks/common_msgs/trunk'}} Continue(y/n): y Overwriting /tmp/rosws_tutorial/.rosinstall Config changed, remember to run 'rosws update common_msgs' to update the folder from svn The command by default tells you what it thinks you have meant, which is generally useful if the workspaces become larger. You can just confirm. ``rosws info`` again shows the current state of your workspace. We will go ahead and check this stack out, as it is fairly small it should not take too long. Pulling entries ~~~~~~~~~~~~~~~ :: $ rosws update common_msgs [common_msgs] Installing https://code.ros.org/svn/ros-pkg/stacks/common_msgs/trunk (None) to /tmp/rosws_tutorial/common_msgs [common_msgs] Done. $ ls common_msgs/ setup.bash setup.sh setup.zsh .. note:: You can also at any time update all your workspace trees just using ``rosws update`` You can now see that the repository was checked out, also using ``rosws info``: :: $ ls -a ./ ../ common_msgs/ .rosinstall .rosinstall.bak setup.bash setup.sh setup.zsh $ rosws info Localname S SCM Version-Spec UID (Spec) URI (Spec) (https://...) --------- - ---- ------------ ----------- ------------------------- common_msgs svn trunk -r39122 code.ros.org/svn/ros-pkg/stacks/common_msgs/ ... You see now the UID (Spec) column contains your current revision. If you see a different revision number, that is okay. We can play with that a bit:: $ svn update common_msgs -r PREV ... $ rosws info Localname S SCM Version-Spec UID (Spec) URI (Spec) (https://...) --------- - ---- ------------ ----------- ------------------------- common_msgs svn trunk -r38989 code.ros.org/svn/ros-pkg/stacks/common_msgs/ ... You should notice that for you, the revision number should have changed as well. We needed use the ``svn`` command here because we changed the ``common_msgs`` version without changes to the .rosinstall file. Setting entry versions: ~~~~~~~~~~~~~~~~~~~~~~~ Let's say you want to stay with one revision for some time, we can specify a revision like this: :: $ rosws set common_msgs --version=-r38935 Change element from: {'svn': {'local-name': 'common_msgs', 'uri': 'https://code.ros.org/svn/ros-pkg/stacks/common_msgs/trunk'}} to {'svn': {'local-name': 'common_msgs', 'version': '-r38935', 'uri': 'https://code.ros.org/svn/ros-pkg/stacks/common_msgs/trunk'}} Continue(y/n): y Overwriting /tmp/rosws_tutorial/.rosinstall Config changed, remember to run 'rosws update common_msgs' to update the folder from svn Again you see the tool asks you to confirm. :: $ rosws info Localname S SCM Version-Spec UID (Spec) URI (Spec) (https://...) --------- - ---- ------------ ----------- ------------------------- common_msgs V svn trunk -r39028 (-r38935) code.ros.org/svn/ros-pkg/stacks/common_msgs/ What you see now in the output of rosws info in the UID column is two numbers. The first is current revision, the second is what is now stated in your .rosinstall. Also notice the Status column ``S`` now shows a ``V``. This indicates some specification mismatch, and it is the quick way to see whether your filesystem matches what is given in your .rosinstall. To clean this up, you could now set the value to the actual value, or run ``rosws update`` to update to the version in the spec, or remove the version spec. We will do the latter using the set command:: $ rosws set common_msgs --version="" Change element from: {'svn': {'local-name': 'common_msgs', 'version': '-r38935', 'uri': 'https://code.ros.org/svn/ros-pkg/stacks/common_msgs/trunk'}} to {'svn': {'local-name': 'common_msgs', 'version': '', 'uri': 'https://code.ros.org/svn/ros-pkg/stacks/common_msgs/trunk'}} Continue(y/n): y Overwriting /tmp/rosws_tutorial/.rosinstall Config changed, remember to run 'rosws update common_msgs' to update the folder from svn Diff and Status: ~~~~~~~~~~~~~~~~ The rosws command also allows to produce diff and status output for the supported SCMs. To see that, we need to change a file. :: $ echo '# foo' >> common_msgs/CMakeLists.txt $ rosws status common_msgs M common_msgs/CMakeLists.txt $ rosws diff common_msgs Index: common_msgs/CMakeLists.txt =================================================================== --- common_msgs/CMakeLists.txt (revision 39028) +++ common_msgs/CMakeLists.txt (working copy) @@ -26,3 +26,4 @@ install(FILES stack.xml stack.yaml DESTINATION share/common_msgs) +# foo $ rosws info Localname S SCM Version-Spec UID (Spec) URI (Spec) (https://...) --------- - ---- ------------ ----------- ------------------------- common_msgs M svn trunk -r39028 code.ros.org/svn/ros-pkg/stacks/common_msgs You can pass multiple folder names to rosws diff and status, or pass none, and it will accumulate the outputs for all trees. Also note how the status column in ``rosws info`` now shows an ``M`` for modified. Detaching Entries ~~~~~~~~~~~~~~~~~ Detached entries have no SCM information associated, running update with them will not affect them. You can detach our common_msgs entry using the set command:: $ rosws set common_msgs --detached Change element from: {'svn': {'local-name': 'common_msgs', 'uri': 'https://code.ros.org/svn/ros-pkg/stacks/common_msgs/trunk'}} to {'other': {'local-name': 'common_msgs'}} Continue(y/n): y Overwriting /tmp/rosws_tutorial/.rosinstall Removing entries ~~~~~~~~~~~~~~~~ Finally you may sometimes want to remove entries from your workspace, there is the ``remove`` command for that:: $ rosws remove common_msgs Overwriting /tmp/rosws_tutorial/.rosinstall Removed entries ['common_msgs'] Updating many ~~~~~~~~~~~~~ Doing several SCM actions at a time can be very time-consuming, and we can gain a lot of time by doing the work in parallel. ``rosws`` allows to checkout or update entries in parallel as well: Here is how to generate a snapshot for one or more entries. We first extend our workspace again:: $ rosws set geometry https://kforge.ros.org/geometry/geometry --hg --version=geometry-1.6.1 $ rosws set common_msgs https://code.ros.org/svn/ros-pkg/stacks/common_msgs/trunk --svn $ rosws update --parallel=2 ``-j=2`` is a shorter version of that option. The default for rosws is not to do parallel work because checking out or updating both may require user interaction, which can get confusing with many threads running at the same time. Getting the most out of info ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Advanced users may want to look at bit more at the info command options. Then we can print the info e.g. of just geometry as yaml or store it in a file:: $ rosws info geometry --yaml > geometry-1.6.1.rosinstall Another interesting feature for scripters is the ``--only`` option:: $ rosws info --only=path,cur_revision /opt/ros/fuerte/share/ros, /opt/ros/fuerte/share, /opt/ros/fuerte/stacks, /opt/ros/fuerte/setup.sh, /tmp/rosws_tutorial/common_msgs,-r39123 /tmp/rosws_tutorial/geometry,53a0d9160982 This yields a CSV representation of the columns you gave, in this case retrieving from SCM providers the current revision id. Adding ROS to workspace ----------------------- If you want to make your workspace a ROS workspace, you will need to do two things: * Manually add core ros stacks to your .rosinstall (copy and paste from /opt/ros//.rosinstall to the TOP of your local .rosinstall file) * regenerate your setup.* files by calling ``rosws regenerate`` Cleanup workspace ----------------- The tutorial ends here, what you can do is deleting the workspace folder: :: $ rm -rf /tmp/rosws_tutorial rosinstall-0.7.8/manifest.xml000066400000000000000000000015041272067315000162530ustar00rootroot00000000000000 rosinstall is a tool to check out ROS source code (or any source code, really) from multiple version control repositories and updating these checkouts. Given a *.rosinstall file that specifies where to get code, rosinstall will check out a working copy for you. We recommend the use of rosinstall when checking out development versions of ROS source code. This package is where the code lives, however it is not expected for users to checkout and use this package directly. It is expected that users use the version available through pypi.python.org. Tully Foote BSD http://ros.org/wiki/rosinstall rosinstall-0.7.8/rosdoc.yaml000066400000000000000000000000531272067315000160760ustar00rootroot00000000000000 - builder: sphinx sphinx_root_dir: doc rosinstall-0.7.8/scripts/000077500000000000000000000000001272067315000154125ustar00rootroot00000000000000rosinstall-0.7.8/scripts/py-rosws-stacks000077500000000000000000000050061272067315000204320ustar00rootroot00000000000000#!/usr/bin/env python # Software License Agreement (BSD License) # # 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 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. # # Revision $Id: rosws 14389 2011-07-20 18:38:40Z tfoote $ # $Author: tfoote $ """%(prog)s is a command to manipulate ROS workspaces. Official usage: %(prog)s CMD [INSTALL_PATH] [ROSINSTALL FILES OR DIRECTORIES] [OPTIONS] rosws will try to infer install path from context "rosws install" replaces the rosinstall command Type '%(prog)s --help' for usage. """ from __future__ import print_function import sys import pkg_resources # else python warning import rosinstall.rosws_stacks_cli from rosinstall.helpers import ROSInstallException from wstool.common import MultiProjectException if __name__ == "__main__": try: sys.exit(rosinstall.rosws_stacks_cli.rosws_stacks_main(sys.argv)) except ROSInstallException as e: sys.stderr.write("ERROR in rosinstall: %s" % str(e)) sys.exit(1) except MultiProjectException as e: sys.stderr.write("ERROR in config: %s" % str(e)) sys.exit(1) rosinstall-0.7.8/scripts/rosbrowse000077500000000000000000000106671272067315000173770ustar00rootroot00000000000000#!/usr/bin/env python # Software License Agreement (BSD License) # # 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 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: kwc """ Library for finding ROS packages, metapackages, and stacks. """ NAME = 'rosbrowse' import yaml import sys try: from os import EX_USAGE except ImportError: EX_USAGE = 0, 1, 2 from rosinstall.distro_locate import get_release_info, get_doc_info, \ get_doc_type, get_doc_www, get_doc_description def cmd_get_release_info(name, distro, options=None): prefix = options.prefix if options is not None and options.prefix else '' return yaml.dump(get_release_info(name, distro, prefix=prefix), default_flow_style=False) def cmd_get_doc_info(name, distro, options=None): prefix = options.prefix if options is not None and options.prefix else '' return yaml.dump(get_doc_info(name, distro, prefix=prefix), default_flow_style=False) def get_type(name, distro, options=None): return get_doc_type(name, distro) def cmd_get_www(name, distro, options=None): return get_doc_www(name, distro) def get_description(name, distro, options=None): return get_doc_description(name, distro) ################################################################################ # Bind library to commandline implementation def _fullusage(): sys.stderr.write(""" %s \trelease_info\tGet rosinstall info of latest release for a package, stack, or metapackage \tdoc_info\tGet rosinstall info of latest documentation source for a package, stack, or metapackage \ttype\t\tCheck whether a name corresponds to a package, stack, or metapackage \twiki\t\tGet the wiki page of a package, stack, or metapackage \tdescription\tGet the description of a package, stack, or metapackage """ % (NAME)) sys.exit(EX_USAGE) _cmds = { # info/rosinstall are now identical 'release_info': cmd_get_release_info, 'doc_info': cmd_get_doc_info, 'type': get_type, 'wiki': cmd_get_www, 'describe': get_description, 'description': get_description, # alias } def rosbrowse_main(): from optparse import OptionParser args = sys.argv # parse command if len(args) < 2: _fullusage() cmd = args[1] if not cmd in _cmds.keys(): _fullusage() parser = OptionParser(usage="usage: %%prog %s " % (cmd), prog=NAME) if cmd in ['release_info', 'doc_info']: parser.add_option("--prefix", dest="prefix", default=False, metavar="PATH", help="path prefix for rosinstall") # noop parse for now. Will matter once we can pass in --distro options, args = parser.parse_args() if len(args) != 3: parser.print_help() sys.exit(-1) distro = args[1] name = args[2] try: print _cmds[cmd](name, distro, options) except Exception as e: sys.stderr.write("%s\n" % e) if __name__ == '__main__': rosbrowse_main() rosinstall-0.7.8/scripts/rosco000077500000000000000000000117121272067315000164670ustar00rootroot00000000000000#!/usr/bin/env python # Software License Agreement (BSD License) # # 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 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. """ # checkout a package/stack, uses same options and roslocate rosco foo --distro=unstable rosco foo --distro=electric --dev # checkout all entries in a rosinstall file rosco -r foo.rosinstall rosco --rosinstall foo.rosinstall # pipe output from roslocate directly roslocate info eigen --distro=unstable | rosco """ from __future__ import print_function import os import sys import yaml from optparse import OptionParser from rosinstall.simple_checkout import checkout_rosinstall from wstool.common import MultiProjectException from rosinstall.locate import get_rosdoc_manifest, get_rosinstall, \ BRANCH_DEVEL, BRANCH_RELEASE, InvalidData def options_to_branch(options): # same logic as roslocate if options.dev: return BRANCH_DEVEL else: return BRANCH_RELEASE def _readfile(filename): """ Parse arg input if options.file is flagged """ with open(filename, 'r') as f: value = f.read() return value def _read_yaml_from_ros_server(name, distro, branch): try: data, type_, url = get_rosdoc_manifest(name, distro) except IOError as ioe: sys.exit('cannot locate information about %s: %s' % (name, ioe)) try: return get_rosinstall(name, data=data, type_=type_, branch=branch) except InvalidData as invd: sys.stderr.write('Using data from url: %s\n' % url) raise invd def rosco_main(): parser = OptionParser(usage=""" Checks out out ros packages or stacks into local directory. \trosco [options] \trosco -r rosco also accepts piped rosinstall input: \troslocate info foo | rosco""") parser.add_option("-r", "--rosinstall", dest="file", default=None, help="checkout entries in rosinstall file") parser.add_option("--distro", dest="distro", default=None, help="fetch information for specific ROS distribution release") parser.add_option("--dev", dest="dev", default=False, action="store_true", help="fetch development branch information") options, args = parser.parse_args() # accept piped input if options.file: # yaml from rosinstall file if args: parser.error("invalid additional args: " % (args)) if not os.path.isfile(options.file): parser.error("no such file %s" % (options.file)) yaml_string = _readfile(options.file) elif not sys.stdin.isatty(): # yaml from piped input yaml_string = sys.stdin.read() else: # yaml from web if len(args) == 0: parser.error('please specify a stack or package') if len(args) != 1: parser.error('you may only specify one input argument') name = args[0] yaml_string = _read_yaml_from_ros_server(name, options.distro, options_to_branch(options)) rosinstall_data = yaml.load(yaml_string) if not rosinstall_data or not type(rosinstall_data) == list: print(rosinstall_data) parser.error("input must be a rosinstall snippet") try: checkout_rosinstall(rosinstall_data, verbose=True) except MultiProjectException as mpe: sys.exit(mpe) if __name__ == '__main__': rosco_main() rosinstall-0.7.8/scripts/rosinstall000077500000000000000000000014421272067315000175330ustar00rootroot00000000000000#!/usr/bin/env python import sys try: from rosinstall.rosinstall_cli import rosinstall_main from rosinstall.helpers import ROSInstallException from wstool.common import MultiProjectException except ImportError as exc: if ('rosinstall' in str(exc) or 'vcstools' in str(exc)): sys.exit("ERROR: Cannot find required rosinstall library version, \ check your installation (also of vcstools) is up-to-date. One frequent cause \ is that rosinstall 0.5 is still installed in /usr/local/lib.\n%s" % exc) raise if __name__ == "__main__": try: sys.exit(not rosinstall_main(sys.argv)) except ROSInstallException as rie: sys.exit("ERROR in rosinstall: %s" % str(rie)) except MultiProjectException as mpe: sys.exit("ERROR in config: %s" % str(mpe)) rosinstall-0.7.8/scripts/roslocate000077500000000000000000000167731272067315000173510ustar00rootroot00000000000000#!/usr/bin/env python # Software License Agreement (BSD License) # # 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 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: kwc """ Library for locating ROS packages and stacks using the centralized index at ROS.org. """ from __future__ import print_function NAME = 'roslocate' import os import sys try: from os import EX_USAGE except ImportError: EX_USAGE = 0, 1, 2 from optparse import OptionParser from rosinstall.locate import get_manifest, \ get_www, get_repo, get_vcs, get_vcs_uri_for_branch,\ get_rosinstall, InvalidData, BRANCH_RELEASE, BRANCH_DEVEL def options_to_branch(options): # we don't let the user express the full range of options at the # command-line, mainly for (1) simplicity and (2) the distro # branch is not reliable. if options.dev and options.rel: sys.exit('only one of --dev and --rel can be used') if options.dev: return BRANCH_DEVEL elif options.rel: return BRANCH_RELEASE return None def cmd_get_rosinstall(name, data, type_, options=None): branch = options_to_branch(options) prefix = options.prefix if options is not None and options.prefix else '' return get_rosinstall(name, data, type_, branch, prefix) def get_type(name, data, type_, options=None): return type_ def cmd_get_vcs_uri(name, data, type_, options=None): return get_vcs_uri_for_branch(data, options_to_branch(options)) def cmd_get_vcs(name, data, type_, options=None): return get_vcs(name, data, type_) def cmd_get_www(name, data, type_, options=None): return get_www(name, data, type_) def get_description(name, data, type_, options=None): if type_ == 'package': return """ Type: package Stack: %s Description: %s URL: %s """ % (data.get('stack', 'none'), data.get('description', ''), data.get('url', '')) elif type_ == 'stack': return """ Type: package Stack: %s Description: %s URL: %s """ % (data.get('stack', 'none'), data.get('description', ''), data.get('url', '')) else: return """ Type: %s Packages: %s Description: %s URL: %s """ % (type_, ", ".join(data.get('packages', [])), data.get('description', ''), data.get('url', '')) def cmd_get_repo(name, data, type_, options=None): return get_repo(name, data, type_) ################################################################################ # Bind library to commandline implementation def _fullusage(parser, error=EX_USAGE): parser.print_help(file=sys.stderr) sys.stderr.write(""" Commands: info\t\tGet rosinstall info of resource vcs\t\tGet name of source control system type\t\tPackage or stack uri\t\tGet source control URI of resource www\t\tGet web page of resource repo\t\tGet repository name of resource describe\tGet description of resource """) sys.exit(error) _cmds = { # info/rosinstall are now identical 'info': cmd_get_rosinstall, 'rosinstall': cmd_get_rosinstall, #alias 'vcs': cmd_get_vcs, 'type': get_type, 'uri': cmd_get_vcs_uri, 'repo': cmd_get_repo, 'www': cmd_get_www, 'describe': get_description, 'description': get_description, # alias } def roslocate_main(): args = sys.argv parser = OptionParser(usage="usage: %prog ", prog=NAME) parser.add_option("--prefix", dest="prefix", default=False, metavar="PATH", help="path prefix for rosinstall") # TODO: distro-specific return values parser.add_option("--distro", dest="distro", help="fetch information for specific ROS distribution release (default: environment variable ROS_DISTRO if defined)") # In this implementation, we're optimizing for the use case where # the user wishes to do a source-based install of a released # stack. The user also has an efficient flag for specifying that # they want a development branch instead. We are not exposing # users to the full range of devel/released/distro branches that # the rosinstall file encodes, mainly because the distro branch is # not reliable with DVCS systems like git. Thus, rosinstall # abstracts the logic for determining what the correct released # branch to use is. parser.add_option("--dev", dest="dev", default=False, action="store_true", help="fetch development branch information") parser.add_option("--rel", dest="rel", default=False, action="store_true", help="fetch release branch information") # parse command if '-h' in args or '--help' in args: # printing commands in OptionParser is a mess _fullusage(parser, error=0) if len(args) < 2: _fullusage(parser) # noop parse for now. Will matter once we can pass in --distro options, args = parser.parse_args() cmd = args[0] if not cmd in _cmds.keys(): _fullusage(parser) if cmd not in ['info', 'rosinstall'] and options.prefix: parser.error('--prefix only allowed with commands info, rosinstall') if len(args) != 2: parser.error("please provide a resource name (package or stack)") name = args[1] if not options.distro: distro = os.environ['ROS_DISTRO'] if 'ROS_DISTRO' in os.environ else None if distro: print('Using ROS_DISTRO: %s' % distro, file=sys.stderr) options.distro = distro else: parser.error("please provide the distro name with --distro DISTRO_NAME") try: data, type_, _ = get_manifest(name, options.distro) except IOError: sys.exit('cannot locate information about %s\n' % (name)) try: print (_cmds[cmd](name, data, type_, options)) sys.stdout.flush() # raises correct error when used in a pipe except InvalidData as e: sys.stderr.write("%s\n" % e) except IOError as ioe: if ioe.errno == 32: sys.exit(ioe) raise if __name__ == '__main__': roslocate_main() rosinstall-0.7.8/scripts/rosws000077500000000000000000000053001272067315000165130ustar00rootroot00000000000000#!/usr/bin/env python # Software License Agreement (BSD License) # # 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 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. # # Revision $Id: rosws 14389 2011-07-20 18:38:40Z tfoote $ # $Author: tfoote $ """%(prog)s is a command to manipulate ROS workspaces. Official usage: %(prog)s CMD [ARGS] [OPTIONS] %(prog)s will try to infer install path from context "%(prog)s init" replaces the rosinstall command Type '%(prog)s --help' for usage. """ from __future__ import print_function import sys try: import rosinstall.rosws_cli from rosinstall.helpers import ROSInstallException from wstool.common import MultiProjectException except ImportError as exc: if ('rosinstall' in str(exc) or 'vcstools' in str(exc)): sys.exit("ERROR: Cannot find required rosinstall library version, \ check your installation (also of vcstools) is up-to-date. One frequent cause \ is that rosinstall 0.5 is still installed in /usr/local/lib.\n%s" % exc) raise if __name__ == "__main__": try: sys.exit(rosinstall.rosws_cli.rosws_main(sys.argv)) except ROSInstallException as rie: sys.exit("ERROR in rosws: %s" % str(rie)) except MultiProjectException as mpe: sys.exit("ERROR in config: %s" % str(mpe)) rosinstall-0.7.8/setup.py000066400000000000000000000024121272067315000154340ustar00rootroot00000000000000from setuptools import setup import imp def get_version(): ver_file = None try: ver_file, pathname, description = imp.find_module('__version__', ['src/rosinstall']) vermod = imp.load_module('__version__', ver_file, pathname, description) version = vermod.version return version finally: if ver_file is not None: ver_file.close() setup(name='rosinstall', version=get_version(), packages=['rosinstall'], package_dir={'': 'src'}, install_requires=['vcstools>=0.1.38', 'pyyaml', 'rosdistro>=0.3.0', 'catkin_pkg', 'wstool>=0.1.12'], scripts=["scripts/rosinstall", "scripts/roslocate", "scripts/rosws", "scripts/rosco"], author="Tully Foote", author_email="tfoote@osrfoundation.org", url="http://wiki.ros.org/rosinstall", download_url="http://download.ros.org/downloads/rosinstall/", keywords=["ROS"], classifiers=["Programming Language :: Python", "Programming Language :: Python :: 2", "Programming Language :: Python :: 3", "License :: OSI Approved :: BSD License"], description="The installer for ROS", long_description="""\ The installer for ROS """, license="BSD") rosinstall-0.7.8/src/000077500000000000000000000000001272067315000145125ustar00rootroot00000000000000rosinstall-0.7.8/src/rosinstall/000077500000000000000000000000001272067315000167045ustar00rootroot00000000000000rosinstall-0.7.8/src/rosinstall/__init__.py000066400000000000000000000031331272067315000210150ustar00rootroot00000000000000# Software License Agreement (BSD License) # # 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 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 wstool.helpers rosinstall-0.7.8/src/rosinstall/__version__.py000066400000000000000000000000221272067315000215310ustar00rootroot00000000000000version = '0.7.8' rosinstall-0.7.8/src/rosinstall/distro_locate.py000066400000000000000000000241151272067315000221140ustar00rootroot00000000000000# Software License Agreement (BSD License) # # 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 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: kwc import rosdistro from rosdistro.manifest_provider import get_release_tag from rospkg import distro as rospkg_distro import yaml try: from urllib.request import urlopen except ImportError: from urllib2 import urlopen BRANCH_RELEASE = 'release' BRANCH_DEVEL = 'devel' class InvalidData(Exception): pass def build_rosinstall(repo_name, uri, vcs_type, version, prefix): """ Build a rosinstall file given some basic information """ rosinstall = [] repo_name = repo_name if not prefix else '/'.join([prefix, repo_name]) if version: rosinstall.append({vcs_type: {'local-name': repo_name, 'uri': uri, 'version': version}}) else: rosinstall.append({vcs_type: {'local-name': repo_name, 'uri': uri}}) # return yaml.dump(rosinstall, default_flow_style=False) return rosinstall def get_wet_info(wet_distro, name): """ Get information about wet packages or stacks """ repos = wet_distro['repositories'] for repo in repos: info = repos[repo] if repo == name or name in info.get('packages', []): return (repo, info) return None def get_dry_info(dry_distro, name): """ Get information about dry stacks """ dry_stacks = dry_distro.get_stacks(True) if name in dry_stacks: stack = dry_stacks[name] if stack.vcs_config.type == 'svn': return (name, stack.vcs_config.release_tag, stack.vcs_config.type, None) else: return (name, stack.vcs_config.anon_repo_uri, stack.vcs_config.type, stack.vcs_config.release_tag) return None def get_release_rosinstall(name, wet_distro, dry_distro, prefix): """ Check if the name is in the wet distro """ info = get_wet_info(wet_distro, name) if info: repo_name, repo_info = info if repo_name == name and 'packages' in repo_info: rosinstall = [] pkg_prefix = '/'.join([prefix, repo_name]) if prefix else repo_name for pkg in repo_info['packages'].keys(): rosinstall.extend(build_rosinstall(pkg, repo_info['url'], 'git', '/'.join( ['release', pkg, repo_info['version'].split('-')[0]]), pkg_prefix)) return rosinstall else: return build_rosinstall( name, repo_info['url'], 'git', '/'.join(['release', name, repo_info['version'].split('-')[0]]), prefix) # Check if the name is in the dry distro info = get_dry_info(dry_distro, name) if info: name, uri, vcs_type, version = info return build_rosinstall(name, uri, vcs_type, version, prefix) return None def get_manifest_yaml(name, distro): # If we didn't find the name, we need to try to find a stack for it url = 'http://ros.org/doc/%s/api/%s/manifest.yaml' % (distro, name) try: return yaml.load(urlopen(url)) except: raise IOError("Could not load a documentation manifest for %s-%s from ros.org\n\ Have you selected a valid distro? Did you spell everything correctly? Is your package indexed on ros.org?\n\ I'm looking here: %s for a yaml file." % (distro, name, url)) def _get_fuerte_release(): """ Please delete me when fuerte is not supported anymore See REP137 about rosdistro files """ url = 'https://raw.github.com/ros/rosdistro/master/releases/fuerte.yaml' try: fuerte_distro = yaml.load(urlopen(url)) except: raise IOError("Could not load the fuerte rosdistro file from github.\n" "Are you sure you've selected a valid distro?\n" "I'm looking for the following file %s" % url) return fuerte_distro def _get_fuerte_rosinstall(name, prefix=None): """ Please delete me when fuerte is not supported anymore See REP137 about rosdistro files """ dry_distro = rospkg_distro.load_distro(rospkg_distro.distro_uri('fuerte')) wet_distro = _get_fuerte_release() # Check to see if the name just exists in one of our rosdistro files rosinstall = get_release_rosinstall(name, wet_distro, dry_distro, prefix) if rosinstall: return rosinstall # If we didn't find the name, we need to try to find a stack for it doc_yaml = get_manifest_yaml(name, 'fuerte') for metapackage in doc_yaml.get('metapackages', []): meta_yaml = get_manifest_yaml(metapackage, 'fuerte') if meta_yaml['package_type'] == 'stack': rosinstall = get_release_rosinstall( metapackage, wet_distro, dry_distro, prefix) if rosinstall: return rosinstall return None def _get_electric_rosinstall(name, prefix=None): """ Please delete me when you don't care at all about electric anymore """ dry_distro = rospkg_distro.load_distro(rospkg_distro.distro_uri('electric')) if _is_dry(dry_distro, name): return get_dry_rosinstall(dry_distro, name, prefix=prefix) # If we didn't find the name, we need to try to find a stack for it doc_yaml = get_manifest_yaml(name, 'electric') for metapackage in doc_yaml.get('metapackages', []): meta_yaml = get_manifest_yaml(metapackage, 'electric') if meta_yaml['package_type'] == 'stack': if _is_dry(dry_distro, metapackage): return get_dry_rosinstall(dry_distro, metapackage, prefix=prefix) return None def _get_rosdistro_release(distro): index = rosdistro.get_index(rosdistro.get_index_url()) return rosdistro.get_distribution_file(index, distro) def _find_repo(release_file, name): for r in release_file.repositories: repo = release_file.repositories[r] if name in repo.package_names: return repo return None def _is_wet(release_file, name): return _find_repo(release_file, name) is not None def _is_dry(dry_distro, name): return get_dry_info(dry_distro, name) is not None def get_wet_rosinstall(release_file, name, prefix=None): repo = _find_repo(release_file, name) if repo is None: # wait, what? return None return build_rosinstall(name, repo.url, 'git', get_release_tag(repo, name), prefix) def get_dry_rosinstall(dry_distro, name, prefix=None): info = get_dry_info(dry_distro, name) if info: name, uri, vcs_type, version = info return build_rosinstall(name, uri, vcs_type, version, prefix) return None def get_release_info(name, distro, prefix=None): """ Steps to check for a released version of the package 1) Look in the wet distro file for the package/stack name, if it's there, return the repo 2) Look in the dry distro file for the package/stack name, if it's there, return the repo 3) Look in the manifest.yaml generated by the documentation indexer to take a best guess at what stack a given package belongs to 4) Look in the distro files again to see if the stack name is there, if it is, return the repo """ # fuerte is different. if distro == 'fuerte': return _get_fuerte_rosinstall(name, prefix=prefix) # electric is ancient. if distro == 'electric': return _get_electric_rosinstall(name, prefix=prefix) wet_distro = _get_rosdistro_release(distro) dry_distro = rospkg_distro.load_distro(rospkg_distro.distro_uri(distro)) # Check to see if the name just exists in one of our rosdistro files if _is_wet(wet_distro, name): return get_wet_rosinstall(wet_distro, name, prefix=prefix) if _is_dry(dry_distro, name): return get_dry_rosinstall(dry_distro, name, prefix=prefix) # If we didn't find the name, we need to try to find a stack for it doc_yaml = get_manifest_yaml(name, distro) for metapackage in doc_yaml.get('metapackages', []): meta_yaml = get_manifest_yaml(metapackage, distro) if meta_yaml['package_type'] == 'stack': if _is_dry(dry_distro, metapackage): return get_dry_rosinstall(dry_distro, metapackage, prefix=prefix) return None def get_doc_info(name, distro, prefix=None): doc_yaml = get_manifest_yaml(name, distro) return build_rosinstall( doc_yaml['repo_name'], doc_yaml['vcs_uri'], doc_yaml['vcs'], doc_yaml.get('vcs_version', ''), prefix) def get_doc_type(name, distro): return get_manifest_yaml(name, distro)['package_type'] def get_doc_www(name, distro): return get_manifest_yaml(name, distro)['url'] def get_doc_description(name, distro): return get_manifest_yaml(name, distro)['description'] rosinstall-0.7.8/src/rosinstall/helpers.py000066400000000000000000000112621272067315000207220ustar00rootroot00000000000000# Software License Agreement (BSD License) # # 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 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 import codecs import subprocess from wstool.config_elements import SetupConfigElement ROSINSTALL_FILENAME = ".rosinstall" class ROSInstallException(Exception): pass def is_path_stack(path): """ @return: True if the path provided is the root of a stack. """ stack_path = os.path.join(path, 'stack.xml') if os.path.isfile(stack_path): return True return False def is_path_ros(path): """ warning: exits with code 1 if stack document is invalid @param path: path of directory to check @type path: str @return: True if path points to the ROS stack @rtype: bool """ if path is None: return False if os.path.basename(path) == 'ros': stack_path = os.path.join(path, 'stack.xml') return os.path.isfile(stack_path) return False def get_ros_root_from_setupfile(path): """ Return the ROS_ROOT if the path is a setup.sh file with an env.sh next to it which sets the ROS_ROOT :returns: path to ROS_ROOT or None """ # For groovy, we rely on setup.sh setting ROS_ROOT, as no more # rosbuild stack 'ros' exists dirpath, basename = os.path.split(path) if basename != 'setup.sh': return None # env.sh exists since fuerte setupfilename = os.path.join(dirpath, 'env.sh') if not os.path.isfile(setupfilename): return None cmd = "%s sh -c 'echo $ROS_ROOT'" % setupfilename local_env = os.environ if 'ROS_ROOT' in local_env: local_env.pop('ROS_ROOT') process = subprocess.Popen(cmd, stdout=subprocess.PIPE, env=local_env, shell=True) out = process.communicate()[0] if sys.version < '3': out_str = codecs.unicode_escape_decode(out)[0] else: out_str = out.decode('utf-8') return out_str.strip() def get_ros_stack_path(config): """ Detect valid ROS_ROOT directories from the config elements""" # need to track actual path, realpath, and source found_paths = set() sources = {} for tree_el in config.get_config_elements(): el_path = tree_el.get_path() if is_path_ros(el_path): found_paths.add(os.path.realpath(el_path)) sources[el_path] = el_path elif isinstance(tree_el, SetupConfigElement): ros_root = get_ros_root_from_setupfile(tree_el.get_local_name()) if ros_root: found_paths.add(os.path.realpath(ros_root)) sources[tree_el.get_local_name()] = ros_root if len(found_paths) > 1: raise ROSInstallException("""\ Multiple ros stacks found in config %s, Please elimate all but one. They come from the following sources: %s\n""" % (found_paths, sources)) elif len(found_paths) == 1: return list(sources.values())[0] return None def get_ros_package_path(config): """ Return the simplifed ROS_PACKAGE_PATH """ code_trees = [] for tree_el in reversed(config.get_config_elements()): if not is_path_ros(tree_el.get_path()): if not os.path.isfile(tree_el.get_path()): code_trees.append(tree_el.get_path()) return code_trees rosinstall-0.7.8/src/rosinstall/locate.py000066400000000000000000000247341272067315000205370ustar00rootroot00000000000000# Software License Agreement (BSD License) # # 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 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: kwc import sys import yaml try: from urllib.request import urlopen except ImportError: from urllib2 import urlopen from catkin_pkg.package import parse_package_string from rosdistro import get_cached_distribution, get_index, get_index_url BRANCH_RELEASE = 'release' BRANCH_DEVEL = 'devel' class InvalidData(Exception): pass def _get_rosinstall_dict(name, data, type_, branch=None, prefix=None): """ From the dict that was read from the online indexer, create a single rosinstall dict. """ # This function takes into account that the way VCS # information was colleted by the indexer has varied a lot # historically (without documentation or announcement thereof), so # it's a mess. ri_entry = None if branch: branch_data = data.get('rosinstalls', None) if branch_data: ri_entry = branch_data.get(branch, None) else: sys.stderr.write( 'Warning: No specific branch data for branch "%s" found, falling back on default checkout\n' % branch) # if we were unable to compute the rosinstall info based on a # desired branch, use the default info instead if ri_entry is None: prepared_rosinstall = data.get('rosinstall', None) if prepared_rosinstall: ri_entry = prepared_rosinstall else: vcs = get_vcs(name, data, type_) vcs_uri = get_vcs_uri(data) if not vcs or not vcs_uri: raise InvalidData( "Missing VCS control information for %s %s, requires vcs[%s] and vcs_uri[%s]" % (type_, name, vcs, vcs_uri)) vcs_version = get_vcs_version(data) ri_entry = {vcs: {'uri': vcs_uri, 'local-name': name } } if vcs_version: ri_entry[vcs]['version'] = vcs_version if prefix: prefix = prefix or '' for _, v in ri_entry.items(): if 'local-name' in v: local_name = v['local-name'] # 3513 # compute path: we can't use os.path.join because rosinstall paths # are always Unix-style. paths = [x for x in (prefix, local_name) if x] path = '/'.join(paths) v['local-name'] = path return ri_entry def get_rosinstall(name, data, type_, branch=None, prefix=None): """ Compute a rosinstall fragment for checkout @param name: resource name @param data: manifest data for resource @param branch: source branch type ('devel' or 'release') @param prefix: checkout filepath prefix @raise InvalidData """ ri_entry = _get_rosinstall_dict(name, data, type_, branch, prefix) return yaml.dump([ri_entry], default_flow_style=False) def get_vcs_uri_for_branch(data, branch=None): """ @param data: rosdoc manifest data @param branch: source branch type ('devel' or 'release') """ ri_entry = None if branch: branch_data = data.get('rosinstalls', None) if branch_data: ri_entry = branch_data.get(branch, None) vcs_type = list(ri_entry.keys())[0] return ri_entry[vcs_type]['uri'] return data.get('vcs_uri', '') def get_vcs(name, data, type_): """ @param name: resource name @param data: rosdoc manifest data @param type_: resource type ('stack' or 'package') """ return data.get('vcs', '') def get_vcs_version(data): return data.get('vcs_version', '') def get_vcs_uri(data): return data.get('vcs_uri', '') def get_repo(name, data, type_): """ @param name: resource name @param data: rosdoc manifest data @param type_: resource type ('stack' or 'package') """ return data.get('repo_name', '') def get_type(data): """ @param data: rosdoc manifest data @return 'stack' of 'package' """ return data.get('package_type', 'package') def get_www(name, data, type_): """ @param name: resource name @param data: rosdoc manifest data @param type_: resource type ('stack' or 'package') """ return data.get('url', '') def get_manifest(stackage_name, distro_name=None): """ Get the repository and manifest data. @param stackage_name: name of package/stack to get manifest information for. get_manifest() gives stacks symbols precedence over package symbols. @type stackage_name: str @param distro_name: name of ROS distribution @type distro_name: str @return: (manifest data, 'package'|'stack'|'repository'). @rtype: ({str: str}, str, str) @raise IOError: if data cannot be loaded """ data = None if distro_name is not None: data = get_manifest_from_rosdistro(stackage_name, distro_name) if data is None: sys.stderr.write('Not found via rosdistro - falling back to information provided by rosdoc\n') data = get_rosdoc_manifest(stackage_name, distro_name) return data def get_manifest_from_rosdistro(package_name, distro_name): """ Get the rosdistro repository data and package information. @param package_name: name of package or repository to get manifest information for. It gives package symbols precedence over repository names. @type package_name: str @param distro_name: name of ROS distribution @type distro_name: str @return: (manifest data, 'package'|'repository'). @rtype: ({str: str}, str, str) @raise IOError: if data cannot be loaded """ data = {} type_ = None index = get_index(get_index_url()) try: distribution_cache = get_cached_distribution(index, distro_name) except RuntimeError as runerr: if (runerr.message.startswith("Unknown release")): return None raise if package_name in distribution_cache.release_packages: pkg = distribution_cache.release_packages[package_name] #print('pkg', pkg.name) pkg_xml = distribution_cache.get_release_package_xml(package_name) pkg_manifest = parse_package_string(pkg_xml) data['description'] = pkg_manifest.description website_url = [u.url for u in pkg_manifest.urls if u.type == 'website'] if website_url: data['url'] = website_url[0] repo_name = pkg.repository_name meta_export = [exp for exp in pkg_manifest.exports if exp.tagname == 'metapackage'] if meta_export: type_ = 'metapackage' else: type_ = 'package' else: repo_name = package_name type_ = 'repository' data['repo_name'] = repo_name if repo_name in distribution_cache.repositories: repo = distribution_cache.repositories[repo_name].release_repository if repo: data['packages'] = repo.package_names if repo_name in distribution_cache.repositories: repo = distribution_cache.repositories[repo_name].source_repository if not repo: return None data['vcs'] = repo.type data['vcs_uri'] = repo.url data['vcs_version'] = repo.version else: return None return (data, type_, None) def get_rosdoc_manifest(stackage_name, distro_name=None): """ Get the rosdoc manifest data and type of stackage_name. @param stackage_name: name of package/stack to get manifest information for. get_manifest() gives stacks symbols precedence over package symbols. @type stackage_name: str @param distro_name: name of ROS distribution @type distro_name: str @return: (manifest data, 'package'|'stack'). @rtype: ({str: str}, str, str) @raise IOError: if data cannot be loaded """ ROSDOC_PREFIX = 'http://ros.org/doc' if distro_name is not None: prefix = '%s/%s' % (ROSDOC_PREFIX, distro_name) else: prefix = ROSDOC_PREFIX data = None url_stack = '%s/api/%s/stack.yaml' % (prefix, stackage_name) url_pack = '%s/api/%s/manifest.yaml' % (prefix, stackage_name) errors = [] # ! loop vars used after loop as well for type_, url in zip(['stack', 'package'], [url_stack, url_pack]): try: streamdata = urlopen(url) data = yaml.load(streamdata) if not data: raise InvalidData( 'No Information available on %s %s at %s' % (type_, stackage_name, url)) # with fuerte, stacks also have manifest.yaml, but have a type flag realtype = data.get('package_type') if realtype: type_ = realtype break except Exception as loope: errors.append((url, loope)) # 1 error is expected when we query package if len(errors) > 1: error = None for (err_url, error) in errors: if error is not None: sys.stderr.write('error contacting %s:\n%s\n' % (err_url, error)) raise error return (data, type_, url) rosinstall-0.7.8/src/rosinstall/rosinstall_cli.py000066400000000000000000000242441272067315000223050ustar00rootroot00000000000000# Software License Agreement (BSD License) # # 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 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. """ usage: rosinstall [OPTIONS] INSTALL_PATH [ROSINSTALL FILES OR DIRECTORIES] see: http://www.ros.org/wiki/rosinstall Common Option: -n or --nobuild (don't perform a 'make core_cools' on the ros stack) Type 'rosinstall --help' for usage. Common invocations: initial checkout: rosinstall ~/ros "http://packages.ros.org/cgi-bin/gen_rosinstall.py?rosdistro=diamondback&variant=ros-full&overlay=no" subsequent update: rosinstall ~/ros """ from __future__ import print_function import os import sys from optparse import OptionParser import yaml import shutil from rosinstall import rosinstall_cmd from wstool import multiproject_cmd from wstool.helpers import ROSINSTALL_FILENAME import rosinstall.__version__ def usage(): print(__doc__ % vars()) exit(1) def rosinstall_main(argv): if len(argv) < 2: usage() args = argv[1:] parser = OptionParser(usage="usage: rosinstall [OPTIONS] INSTALL_PATH [ROSINSTALL FILES OR DIRECTORIES]\n\n\ rosinstall does the following:\n\ 1. Merges all URIs into new or existing .rosinstall file at PATH\n\ 2. Checks out or updates all version controlled URIs\n\ 3. If ros stack is installed from source, calls rosmake after checkout or updates.\n\ 4. Generates/overwrites updated setup files\n\n\ If running with --catkin mode:\ 1. Merges all URIs into new or existing .rosinstall file at PATH\n\ 2. Checks out or updates all version controlled URIs\n\ 4. Generates/overwrites updated setup files and creates CMakeLists.txt at the root.\n\n\ URIs can be web urls to remote .rosinstall files, local .rosinstall files,\n\ git, svn, bzr, hg URIs, or other (local directories)\n\ Later URIs will shadow packages of earlier URIs.\n", epilog="See: http://www.ros.org/wiki/rosinstall for details\n") parser.add_option("-c", "--catkin", dest="catkin", default=False, help="Declare this is a catkin build.", action="store_true") parser.add_option("--cmake-prefix-path", dest="catkinpp", default=None, help="Where to set the CMAKE_PREFIX_PATH, implies --catkin", action="store") parser.add_option("--version", dest="version", default=False, help="display version information", action="store_true") parser.add_option("--verbose", dest="verbose", default=False, help="display more information", action="store_true") parser.add_option("-n", "--nobuild", dest="nobuild", default=False, help="skip the build step for the ROS stack", action="store_true") parser.add_option("--rosdep-yes", dest="rosdep_yes", default=False, help="Pass through --rosdep-yes to rosmake", action="store_true") parser.add_option("--continue-on-error", dest="robust", default=False, help="Continue despite checkout errors", action="store_true") parser.add_option("--delete-changed-uris", dest="delete_changed", default=False, help="Delete the local copy of a directory before changing uri.", action="store_true") parser.add_option("--abort-changed-uris", dest="abort_changed", default=False, help="Abort if changed uri detected", action="store_true") parser.add_option("--backup-changed-uris", dest="backup_changed", default='', help="backup the local copy of a directory before changing uri to this directory.", action="store") parser.add_option("--diff", dest="vcs_diff", default=False, help="shows a combined diff over all SCM entries", action="store_true") parser.add_option("--status", dest="vcs_status", default=False, help="shows a combined status command over all SCM entries", action="store_true") parser.add_option("--status-untracked", dest="vcs_status_untracked", default=False, help="shows a combined status command over all SCM entries, also showing untracked files", action="store_true") parser.add_option("-j", "--parallel", dest="jobs", default=1, help="How many parallel threads to use for installing", action="store") parser.add_option( "--generate-versioned-rosinstall", dest="generate_versioned", default=None, help="generate a versioned rosinstall file", action="store") (options, args) = parser.parse_args(args) if options.version: print("rosinstall %s\n%s" % (rosinstall.__version__.version, multiproject_cmd.cmd_version())) sys.exit(0) if len(args) < 1: parser.error("rosinstall requires at least 1 argument") mode = 'prompt' if options.delete_changed: mode = 'delete' if options.abort_changed: if mode == 'delete': parser.error( "delete-changed-uris is mutually exclusive with abort-changed-uris") mode = 'abort' if options.backup_changed != '': if mode == 'delete': parser.error( "delete-changed-uris is mutually exclusive with backup-changed-uris") if mode == 'abort': parser.error( "abort-changed-uris is mutually exclusive with backup-changed-uris") mode = 'backup' # Catkin must be enabled if catkinpp is set if options.catkinpp: options.catkin = True # Get the path to the rosinstall options.path = os.path.abspath(args[0]) config_uris = args[1:] config = multiproject_cmd.get_config(basepath=options.path, additional_uris=config_uris, config_filename=ROSINSTALL_FILENAME) if options.generate_versioned: filename = os.path.abspath(options.generate_versioned) source_aggregate = multiproject_cmd.cmd_snapshot(config) with open(filename, 'w') as fhand: fhand.write(yaml.safe_dump(source_aggregate)) print("Saved versioned rosinstall of current directory %s to %s" % (options.path, filename)) return True if options.vcs_diff: difflist = multiproject_cmd.cmd_diff(config) alldiff = [] for entrydiff in difflist: if entrydiff['diff'] is not None and entrydiff['diff'] != '': alldiff.append(entrydiff['diff']) print('\n'.join(alldiff)) return True if options.vcs_status or options.vcs_status_untracked: statuslist = multiproject_cmd.cmd_status( config, untracked=options.vcs_status_untracked) allstatus = "" for entrystatus in statuslist: if entrystatus['status'] is not None: allstatus += entrystatus['status'] print(allstatus, end='') return True print("rosinstall operating on", options.path, "from specifications in rosinstall files ", ", ".join(config_uris)) # includes ROS specific files print("(Over-)Writing %s" % os.path.join(options.path, ROSINSTALL_FILENAME)) if(os.path.isfile(os.path.join(options.path, ROSINSTALL_FILENAME))): shutil.move(os.path.join(options.path, ROSINSTALL_FILENAME), "%s.bak" % os.path.join(options.path, ROSINSTALL_FILENAME)) rosinstall_cmd.cmd_persist_config(config) ## install or update each element install_success = multiproject_cmd.cmd_install_or_update( config, backup_path=options.backup_changed, mode=mode, robust=options.robust, num_threads=int(options.jobs), verbose=options.verbose) rosinstall_cmd.cmd_generate_ros_files( config, options.path, options.nobuild, options.rosdep_yes, options.catkin, options.catkinpp) if not install_success: print("Warning: installation encountered errors, but --continue-on-error was requested. Look above for warnings.") print("\nrosinstall update complete.") if (options.catkin is False and options.catkinpp is None): print("\n\nNow, type 'source %s/setup.bash' to set up your environment.\nAdd that to the bottom of your ~/.bashrc to set it up every time.\n\nIf you are not using bash please see http://www.ros.org/wiki/rosinstall/NonBashShells " % os.path.abspath(options.path)) return True rosinstall-0.7.8/src/rosinstall/rosinstall_cmd.py000066400000000000000000000115761272067315000223050ustar00rootroot00000000000000# Software License Agreement (BSD License) # # 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 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 subprocess from wstool.multiproject_cmd import cmd_persist_config as multipersist from rosinstall import setupfiles from wstool.helpers import ROSINSTALL_FILENAME from rosinstall.helpers import is_path_ros def cmd_persist_config(config, config_filename=ROSINSTALL_FILENAME, header=''): ## Save .rosinstall header = (header or '') + """\ # IT IS UNLIKELY YOU WANT TO EDIT THIS FILE BY HAND, # UNLESS FOR REMOVING ENTRIES. # IF YOU WANT TO CHANGE THE ROS ENVIRONMENT VARIABLES # USE THE rosinstall TOOL INSTEAD. # IF YOU CHANGE IT, USE rosinstall FOR THE CHANGES TO TAKE EFFECT """ multipersist(config, config_filename, header) def _ros_requires_boostrap(config): """ Tests whether workspace contains a core ros stack, to decide whether to rosmake :param config: workspace config object """ for entry in config.get_source(): if is_path_ros(os.path.join(config.get_base_path(), entry.get_local_name())): # we assume that if any of the elements we installed came # from a VCS source, a bootsrap might be useful if entry.get_scmtype() is not None: return True return False def cmd_maybe_refresh_ros_files(config): """ Regenerates setup.* files if they exist already :param config: workspace config object """ if (os.path.isfile(os.path.join(config.get_base_path(), 'setup.sh'))): print("Overwriting setup.sh, setup.bash, and setup.zsh in %s" % config.get_base_path()) setupfiles.generate_setup(config, no_ros_allowed=True) def cmd_generate_ros_files(config, path, nobuild=False, rosdep_yes=False, catkin=False, catkinpp=None, no_ros_allowed=False): """ Generates ROS specific setup files :param nobuild: Unless True, invokes rosmake to build all packages if core ROS stack is detected :param rosdep_yes: If True, adds --rosdep-yes to rosmake command :param catkin: if true, generates catkin(fuerte) CMakeLists.txt instead of invoking rosmake :param catkinpp: Prefix path for catkin if generating for catkin :param no_ros_allowed: if true, does not look for a core ros stack """ # Catkin must be enabled if catkinpp is set if catkinpp is not None: catkin = True ## bootstrap the build if installing ros if catkin: setupfiles.generate_catkin_cmake(path, catkinpp) else: # DRY install case ## Generate setup.sh and save print("(Over-)Writing setup.sh, setup.bash, and setup.zsh in %s" % config.get_base_path()) setupfiles.generate_setup(config, no_ros_allowed) if _ros_requires_boostrap(config) and not nobuild: print("Bootstrapping ROS build") rosdep_yes_insert = "" if rosdep_yes: rosdep_yes_insert = " --rosdep-yes" ros_comm_insert = "" if 'ros_comm' in [os.path.basename(tree.get_path()) for tree in config.get_config_elements()]: print("Detected ros_comm bootstrapping it too.") ros_comm_insert = " ros_comm" cmd = ("source %s && rosmake ros%s --rosdep-install%s" % (os.path.join(path, 'setup.sh'), ros_comm_insert, rosdep_yes_insert)) subprocess.check_call(cmd, shell=True, executable='/bin/bash') rosinstall-0.7.8/src/rosinstall/rosws_cli.py000066400000000000000000000473641272067315000213000ustar00rootroot00000000000000# Software License Agreement (BSD License) # # 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 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. """%(prog)s is a command to manipulate ROS workspaces. %(prog)s replaces its predecessor rosinstall. Official usage: %(prog)s CMD [ARGS] [OPTIONS] %(prog)s will try to infer install path from context Type '%(prog)s help' for usage. """ from __future__ import print_function import os import sys import yaml from optparse import OptionParser from wstool.cli_common import get_info_list, get_info_table, \ get_info_table_raw_csv, get_workspace, ONLY_OPTION_VALID_ATTRS import rosinstall.rosinstall_cmd as rosinstall_cmd from wstool.multiproject_cmd import get_config, cmd_install_or_update, \ cmd_snapshot, cmd_version, cmd_info, cmd_find_unmanaged_repos import rosinstall.__version__ from wstool.common import MultiProjectException, select_elements from wstool.helpers import ROSINSTALL_FILENAME from rosinstall.helpers import get_ros_package_path, get_ros_stack_path from wstool.multiproject_cli import MultiprojectCLI, __MULTIPRO_CMD_DICT__, \ __MULTIPRO_CMD_HELP_LIST__, __MULTIPRO_CMD_ALIASES__, \ IndentedHelpFormatterWithNL, list_usage ## This file adds or extends commands from multiproject_cli where ROS ## specific output has to be generated. # extend the commands of multiproject __ROSWS_CMD_DICT__ = {} __ROSWS_CMD_DICT__.update(__MULTIPRO_CMD_DICT__) __ROSWS_CMD_DICT__["regenerate"] = "create ROS workspace specific setup files" __ROSWS_CMD_HELP_LIST__ = __MULTIPRO_CMD_HELP_LIST__[:] __ROSWS_CMD_HELP_LIST__.extend([None, 'regenerate']) _PROGNAME = 'rosws' _VARNAME = 'ROS_WORKSPACE' class RoswsCLI(MultiprojectCLI): def __init__(self, config_filename=ROSINSTALL_FILENAME, progname=_PROGNAME): MultiprojectCLI.__init__(self, progname=progname, config_filename=config_filename, allow_other_element=True, config_generator=rosinstall_cmd.cmd_persist_config) def cmd_init(self, argv): if self.config_filename is None: print('Error: Bug: config filename required for init') return 1 parser = OptionParser( usage="""usage: %s init [TARGET_PATH [SOURCE_PATH]]?""" % self.progname, formatter=IndentedHelpFormatterWithNL(), description=__MULTIPRO_CMD_DICT__["init"] + """ %(prog)s init does the following: 1. Reads folder/file/web-uri SOURCE_PATH looking for a rosinstall yaml 2. Creates new %(cfg_file)s file at TARGET-PATH 3. Generates ROS setup files SOURCE_PATH can e.g. be a folder like /opt/ros/electric If PATH is not given, uses current dir. Examples: $ %(prog)s init ~/fuerte /opt/ros/fuerte """ % {'cfg_file': self.config_filename, 'prog': self.progname}, epilog="See: http://www.ros.org/wiki/rosinstall for details\n") parser.add_option("-c", "--catkin", dest="catkin", default=False, help="Declare this is a catkin build.", action="store_true") parser.add_option("--cmake-prefix-path", dest="catkinpp", default=None, help="Where to set the CMAKE_PREFIX_PATH", action="store") parser.add_option("--continue-on-error", dest="robust", default=False, help="Continue despite checkout errors", action="store_true") parser.add_option("-j", "--parallel", dest="jobs", default=1, help="How many parallel threads to use for installing", action="store") (options, args) = parser.parse_args(argv) if len(args) < 1: target_path = '.' else: target_path = args[0] if not os.path.isdir(target_path): if not os.path.exists(target_path): os.mkdir(target_path) else: print('Error: Cannot create in target path %s ' % target_path) if os.path.exists(os.path.join(target_path, self.config_filename)): print('Error: There already is a workspace config file %s at "%s". Use %s install/modify.' % (self.config_filename, target_path, self.progname)) return 1 if len(args) > 2: parser.error('Too many arguments') config_uris = [] if len(args) == 2: config_uris.append(args[1]) if len(config_uris) > 0: print('Using ROS_ROOT: %s' % config_uris[0]) config = get_config(basepath=target_path, additional_uris=config_uris, config_filename=self.config_filename) # includes ROS specific files print("Writing %s" % os.path.join(config.get_base_path(), self.config_filename)) rosinstall_cmd.cmd_persist_config(config) ## install or update each element install_success = cmd_install_or_update( config, robust=False, num_threads=int(options.jobs)) rosinstall_cmd.cmd_generate_ros_files(config, target_path, nobuild=True, rosdep_yes=False, catkin=options.catkin, catkinpp=options.catkinpp, no_ros_allowed=True) if not install_success: print("Warning: installation encountered errors, but --continue-on-error was requested. Look above for warnings.") print("\nrosinstall update complete.") if (options.catkin is False and options.catkinpp is None): print("\nType 'source %s/setup.bash' to change into this environment. Add that source command to the bottom of your ~/.bashrc to set it up every time you log in.\n\nIf you are not using bash please see http://www.ros.org/wiki/rosinstall/NonBashShells " % os.path.abspath(target_path)) return 0 def cmd_regenerate(self, target_path, argv, config=None): parser = OptionParser(usage="usage: %s regenerate" % self.progname, formatter=IndentedHelpFormatterWithNL(), description=__MULTIPRO_CMD_DICT__["remove"] + """ this command without options generates files setup.sh, setup.bash and setup.zsh. Note that doing this is unnecessary in general, as these files do not change anymore, unless you change from one ROS distro to another (which you should never do like this, create a separate new workspace instead), or you deleted or modified any of those files accidentally. """, epilog="See: http://www.ros.org/wiki/rosinstall for details\n") parser.add_option("-c", "--catkin", dest="catkin", default=False, help="Declare this is a catkin build.", action="store_true") parser.add_option("--cmake-prefix-path", dest="catkinpp", default=None, help="Where to set the CMAKE_PREFIX_PATH", action="store") # -t option required here for help but used one layer above, see cli_common parser.add_option("-t", "--target-workspace", dest="workspace", default=None, help="which workspace to use", action="store") (options, args) = parser.parse_args(argv) if len(args) > 0: print("Error: Too many arguments.") print(parser.usage) return -1 if config is None: config = get_config( target_path, additional_uris=[], config_filename=self.config_filename) elif config.get_base_path() != target_path: raise MultiProjectException( "Config path does not match %s %s " % (config.get_base_path(), target_path)) rosinstall_cmd.cmd_generate_ros_files(config, target_path, nobuild=True, rosdep_yes=False, catkin=options.catkin, catkinpp=options.catkinpp, no_ros_allowed=True) return 0 def cmd_info(self, target_path, argv, reverse=True, config=None): # similar to multiproject_cli except shows ros-pkg-path # options parser = OptionParser( usage="usage: %s info [localname]* [OPTIONS]" % self.progname, formatter=IndentedHelpFormatterWithNL(), description=__MULTIPRO_CMD_DICT__["info"] + """ The Status (S) column shows x for missing L for uncommited (local) changes V for difference in version and/or remote URI C for difference in local and remote versions The 'Version-Spec' column shows what tag, branch or revision was given in the .rosinstall file. The 'UID' column shows the unique ID of the current (and specified) version. The 'URI' column shows the configured URL of the repo. If status is V, the difference between what was specified and what is real is shown in the respective column. For SVN entries, the url is split up according to standard layout (trunk/tags/branches). The ROS_PACKAGE_PATH follows the order of the table, earlier entries overlay later entries. When given one localname, just show the data of one element in list form. This also has the generic properties element which is usually empty. The --only option accepts keywords: %(opts)s Examples: $ %(prog)s info -t ~/ros/fuerte $ %(prog)s info robot_model $ %(prog)s info --yaml $ %(prog)s info --only=path,cur_uri,cur_revision robot_model geometry """ % {'prog': self.progname, 'opts': ONLY_OPTION_VALID_ATTRS}, epilog="See: http://www.ros.org/wiki/rosinstall for details\n") parser.add_option( "--root", dest="show_ws_root", default=False, help="Show workspace root path", action="store_true") parser.add_option( "--data-only", dest="data_only", default=False, help="Does not provide explanations", action="store_true") parser.add_option( "--no-pkg-path", dest="no_pkg_path", default=False, help="Suppress ROS_PACKAGE_PATH.", action="store_true") parser.add_option( "--pkg-path-only", dest="pkg_path_only", default=False, help="Shows only ROS_PACKAGE_PATH separated by ':'. Supercedes all other options.", action="store_true") parser.add_option( "--only", dest="only", default=False, help="Shows comma-separated lists of only given comma-separated attribute(s).", action="store") parser.add_option( "--yaml", dest="yaml", default=False, help="Shows only version of single entry. Intended for scripting.", action="store_true") parser.add_option( "--fetch", dest="fetch", default=False, help="When used, retrieves version information from remote (takes longer).", action="store_true") parser.add_option( "-u", "--untracked", dest="untracked", default=False, help="Also show untracked files as modifications", action="store_true") # -t option required here for help but used one layer above, see cli_common parser.add_option( "-t", "--target-workspace", dest="workspace", default=None, help="which workspace to use", action="store") parser.add_option( "-m", "--managed-only", dest="unmanaged", default=True, help="only show managed elements", action="store_false") (options, args) = parser.parse_args(argv) if config is None: config = get_config( target_path, additional_uris=[], config_filename=self.config_filename) elif config.get_base_path() != target_path: raise MultiProjectException("Config path does not match %s %s " % (config.get_base_path(), target_path)) if options.show_ws_root: print(config.get_base_path()) return 0 if args == []: args = None if options.pkg_path_only: print(":".join(get_ros_package_path(config))) return 0 if options.no_pkg_path: header = 'workspace: %s\nROS_ROOT: %s' % (target_path, get_ros_stack_path(config)) print(header) return 0 elif options.only: only_options = options.only.split(",") if only_options == '': parser.error('No valid options given') lines = get_info_table_raw_csv(config, properties=only_options, localnames=args) print('\n'.join(lines)) return 0 elif options.yaml: source_aggregate = cmd_snapshot(config, localnames=args) print(yaml.safe_dump(source_aggregate), end='') return 0 # this call takes long, as it invokes scms. outputs = cmd_info(config, localnames=args, untracked=options.untracked, fetch=options.fetch) if args and len(args) == 1: # if only one element selected, print just one line print(get_info_list(config.get_base_path(), outputs[0], options.data_only)) return 0 header = 'workspace: %s\nROS_ROOT: %s' % (target_path, get_ros_stack_path(config)) print(header) table = get_info_table(config.get_base_path(), outputs, options.data_only, reverse=reverse) if table is not None and table != '': print("\n%s" % table) if options.unmanaged: outputs2 = cmd_find_unmanaged_repos(config) table2 = get_info_table(config.get_base_path(), outputs2, options.data_only, reverse=reverse, unmanaged=True) if table2 is not None and table2 != '': print("\nAlso detected these repositories in the workspace, add using '%s set':\n\n%s" % (self.progname, table2)) return 0 def rosws_main(argv=None, usage=None): """ Calls the function corresponding to the first argument. :param argv: sys.argv by default :param usage: function printing usage string, multiproject_cli.list_usage by default """ if argv is None: argv = sys.argv if (sys.argv[0] == '-c'): sys.argv = [_PROGNAME] + sys.argv[1:] if '--version' in argv: print("%s: \t%s\n%s" % (_PROGNAME, rosinstall.__version__.version, cmd_version())) sys.exit(0) if not usage: usage = lambda: print(list_usage(progname=_PROGNAME, description=__doc__, command_keys=__ROSWS_CMD_HELP_LIST__, command_helps=__ROSWS_CMD_DICT__, command_aliases=__MULTIPRO_CMD_ALIASES__)) workspace = None if len(argv) < 2: try: workspace = get_workspace(argv, os.getcwd(), config_filename=ROSINSTALL_FILENAME, varname=_VARNAME) argv.append('info') except MultiProjectException as e: print(str(e)) usage() return 0 if argv[1] in ['--help', '-h']: usage() return 0 try: command = argv[1] args = argv[2:] if command == 'help': if len(argv) < 3: usage() return 0 else: command = argv[2] args = argv[3:] args.insert(0, "--help") # help help if command == 'help': usage() return 0 cli = RoswsCLI() # commands for which we do not infer target workspace commands = {'init': cli.cmd_init} # commands which work on a workspace ws_commands = { 'info': cli.cmd_info, 'remove': cli.cmd_remove, 'regenerate': cli.cmd_regenerate, 'set': cli.cmd_set, 'merge': cli.cmd_merge, 'foreach': cli.cmd_foreach, 'scrape': cli.cmd_scrape, 'diff': cli.cmd_diff, 'status': cli.cmd_status, 'update': cli.cmd_update} for label in list(ws_commands.keys()): alias = __MULTIPRO_CMD_ALIASES__.get(label, None) if alias: ws_commands[alias] = ws_commands[label] if command not in commands and command not in ws_commands: if os.path.exists(command): args = ['-t', command] + args command = 'info' else: if command.startswith('-'): print("First argument must be name of a command: %s" % command) else: print("Error: unknown command: %s" % command) usage() return 1 if command in commands: return commands[command](args) else: if workspace is None and not '--help' in args and not '-h' in args: workspace = get_workspace(args, os.getcwd(), config_filename=ROSINSTALL_FILENAME, varname=_VARNAME) return ws_commands[command](workspace, args) except KeyboardInterrupt: return 1 rosinstall-0.7.8/src/rosinstall/rosws_stacks_cli.py000066400000000000000000000370361272067315000226430ustar00rootroot00000000000000# Software License Agreement (BSD License) # # 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 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 import distutils import shutil from subprocess import Popen, PIPE from optparse import OptionParser import yaml from rosinstall.helpers import ROSInstallException, ROSINSTALL_FILENAME from wstool.common import MultiProjectException from wstool.cli_common import get_workspace import rosinstall.rosws_cli from rosinstall.rosinstall_cmd import cmd_persist_config from wstool.multiproject_cmd import get_config, cmd_install_or_update import wstool.config_yaml def get_stack_element_in_config(config, stack): """ The path_spec of a config element if it is named like stack and has a root level file named stack.xml """ for entry in config.get_config_elements(): if entry.get_local_name() == stack: if os.path.isfile(os.path.join(entry.get_path(), 'stack.xml')): return entry else: return None return None def roslocate_info(stack, distro, dev): """ Looks up stack yaml on the web :raises: ROSInstallException on errors """ # TODO: use roslocate from code cmd = ['roslocate', 'info', '--distro=%s' % (distro), stack] if dev is True: cmd.append('--dev') try: proc = Popen(cmd, stdout=PIPE, stderr=PIPE) except OSError as exc: raise ROSInstallException( '%s\nfailed to execute roslocate; is your ROS environment configured?' % (exc)) stdout, stderr = proc.communicate() if proc.returncode != 0: sys.stderr.write('[rosws] Warning: failed to locate stack "%s" in distro "%s". Falling back on non-distro-specific search; compatibility problems may ensue.\n' % (stack, distro)) # Could be that the stack hasn't been released; try roslocate # again, without specifying the distro. cmd = ['roslocate', 'info', stack] if dev is True: cmd.append('--dev') try: proc = Popen(cmd, stdout=PIPE, stderr=PIPE) except OSError as exc: raise ROSInstallException( '%s\nfailed to execute roslocate; is your ROS environment configured?' % (exc)) stdout, stderr = proc.communicate() if proc.returncode != 0: raise ROSInstallException('roslocate failed: %s' % (stderr)) return yaml.load(stdout) def get_ros_stack_version(): """ Reads/Infers the ros stack version. Avoid using this function if you can. """ # TODO: switch to `rosversion -d` after it's been released (r14279, # r14280) cmd = ['rosversion', 'ros'] try: proc = Popen(cmd, stdout=PIPE, stderr=PIPE) except OSError as exc: raise ROSInstallException( '%s\nfailed to execute rosversion; is your ROS environment configured?' % (exc)) stdout, stderr = proc.communicate() if proc.returncode != 0: raise ROSInstallException('rosversion failed: %s' % (stderr)) ver = distutils.version.StrictVersion(stdout).version if len(ver) < 2: raise ROSInstallException('invalid ros version: %s' % (stdout)) return ver def rosversion_to_distro_name(ver): """ Reads/Infers the distro name from ROS / or the ros stack version. Avoid using this function if you can. """ if len(ver) < 2: raise ROSInstallException('invalid ros version: %s' % (ver)) major, minor = ver[0:2] if major == 1 and minor == 10: return 'groovy' if major == 1 and minor == 8: return 'fuerte' if major == 1 and minor == 6: return 'electric' elif major == 1 and minor == 5: return 'unstable' elif major == 1 and minor == 4: return 'diamondback' else: raise ROSInstallException('unknown ros version: %s' % (ver)) def get_dependent_stacks(stack): """ Calls rosstack depends-on to get a list of dependance stacks. Avoid using this function if you can. """ # roslib.stacks doesn't expose the dependency parts of rosstack, so # we'll call it manually cmd = ['rosstack', 'depends-on', stack] try: proc = Popen(cmd, stdout=PIPE, stderr=PIPE) except OSError as exc: raise ROSInstallException( '%s\nfailed to execute rosstack; is your ROS environment configured?' % (exc)) stdout, stderr = proc.communicate() if proc.returncode != 0: raise ROSInstallException('rosstack failed: %s' % (stderr)) # Make sure to exclude empty lines deps = [] for line in stdout.splitlines(): if len(line) > 0: deps.append(line) return deps def cmd_add_stack(config, stackname, released=False, recurse=False): """ Attempts to get ROS stack from source if it is not already in config. Attempts the same for all stacks it depents, if recurse is given. Fails if any stack failed. :param released: use the released or the dev version :param recurse: also get dependant version :returns: True if stack has been added """ def _add_stack(config, stackname, distro, released=False): stack_element = get_stack_element_in_config(config, stackname) if stack_element is not None: print("stack %stackname already in config at %s" % (stackname, stack_element.get_path())) return False yaml_dict = roslocate_info(stackname, distro, not released) if yaml_dict is not None and len(yaml_dict) > 0: path_spec = wstool.config_yaml.get_path_spec_from_yaml(yaml_dict[0]) if config.add_path_spec(path_spec, merge_strategy="MergeKeep") is False: print("Config did not add element %s" % path_spec) return False return True print("roslocate did not return anything") return False ver = get_ros_stack_version() distro = rosversion_to_distro_name(ver) if _add_stack(config, stackname, distro, released) is False: return False if recurse: deps = get_dependent_stacks(stackname) # Also switch anything that depends on this stack for stack in deps: _add_stack(config, stack, distro=distro, released=released) return True def cmd_delete_stack(config, stackname, delete=False, recurse=False): """ Attempts to get ROS stack from source if it is not already in config. Attempts the same for all stacks it depents, if recurse is given. Fails if any stack failed. :param released: use the released or the dev version :param recurse: also get dependant version :returns: True if stack has been added """ def _del_stack(config, stackname, delete=False): stack_element = get_stack_element_in_config(config, stackname) if stack_element is None: print("stack not in config: %s " % stackname) return False config.remove_element(stack_element.get_local_name()) if delete: # TODO confirm each delete shutil.rmtree(os.path.join(config.base_path, stackname), ignore_errors=True) return True if _del_stack(config, stackname, delete) is False: return False if recurse: deps = get_dependent_stacks(stackname) # Also switch anything that depends on this stack for stack in deps: _del_stack(config, stack, delete) return True class RosWsStacksCLI(): def __init__(self): self.config_filename = ROSINSTALL_FILENAME def cmd_add_stack(self, target_path, argv): parser = OptionParser(usage="usage: rosws add-stack [PATH] localname", epilog="See: http://www.ros.org/wiki/rosinstall for details\n") parser.add_option("-N", "--non-recursive", dest="norecurse", default=False, help="don't change configuration for dependent stacks", action="store_true") parser.add_option("--released", dest="released", default=False, help="Pull stack from release tag instead of development branch", action="store_true") parser.add_option("--continue-on-error", dest="robust", default=False, help="Continue despite checkout errors", action="store_true") parser.add_option("--delete-changed-uris", dest="delete_changed", default=False, help="Delete the local copy of a directory before changing uri.", action="store_true") parser.add_option("--abort-changed-uris", dest="abort_changed", default=False, help="Abort if changed uri detected", action="store_true") parser.add_option("--backup-changed-uris", dest="backup_changed", default='', help="backup the local copy of a directory before changing uri to this directory.", action="store") (options, args) = parser.parse_args(argv) mode = 'prompt' if options.delete_changed: mode = 'delete' if options.abort_changed: if mode == 'delete': parser.error( "delete-changed-uris is mutually exclusive with abort-changed-uris") mode = 'abort' if options.backup_changed != '': if mode == 'delete': parser.error( "delete-changed-uris is mutually exclusive with backup-changed-uris") if mode == 'abort': parser.error( "abort-changed-uris is mutually exclusive with backup-changed-uris") mode = 'backup' if len(args) < 1: print("Error: Too few arguments.") print(parser.usage) return -1 if len(args) > 1: print("Error: Too many arguments.") print(parser.usage) return -1 stack = args[0] config = get_config( target_path, [], config_filename=self.config_filename) if cmd_add_stack(config, stack, released=options.released, recurse=(not options.norecurse)) is True: cmd_persist_config(config, self.config_filename) # install or update each element install_success = cmd_install_or_update( config, backup_path=options.backup_changed, mode=mode, robust=options.robust) if install_success: return 0 return 1 def cmd_delete_stack(self, target_path, argv): parser = OptionParser( usage="usage: rosws delete-stack [PATH] localname", epilog="See: http://www.ros.org/wiki/rosinstall for details\n") parser.add_option("-N", "--non-recursive", dest="norecurse", default=False, help="don't change configuration for dependent stacks", action="store_true") parser.add_option("-d", "--delete-working-copies", dest="delete", default=False, help="when deleting a stack from the configuration, also delete the working copy (DANGEROUS!)", action="store_true") (options, args) = parser.parse_args(argv) if len(args) < 1: print("Error: Too few arguments.") print(parser.usage) return -1 if len(args) > 1: print("Error: Too many arguments.") print(parser.usage) return -1 uri = args[0] config = get_config( target_path, [], config_filename=self.config_filename) if cmd_delete_stack(config, uri, delete=options.delete, recurse=(not options.norecurse)): cmd_persist_config(config, self.config_filename) return 0 return 1 def usage(): print("""%(prog)s is an experimental command to add and remove stack from ROS workspaces. Usage: %(prog)s add [INSTALL_PATH] [STACK] [OPTIONS] %(prog)s delete [INSTALL_PATH] [STACK] [OPTIONS] Type '%(prog)s --help' for usage. """ % {'prog': 'rosws-stacks'}) def rosws_stacks_main(argv=None): """ Calls the function corresponding to the first argument. """ if argv is None: argv = sys.argv if ('--help' in argv): usage() return 0 if len(argv) < 2: try: workspace = get_workspace(argv, os.getcwd(), config_filename=ROSINSTALL_FILENAME, varname="ROS_WORKSPACE") argv.append('info') except MultiProjectException as exc: print(str(exc)) usage() return 0 try: command = argv[1] args = argv[2:] if command == 'help': if len(argv) < 3: usage() return 0 else: command = argv[2] args = argv[3:] args.insert(0, "-h") cli = RosWsStacksCLI() commands = {'add': cli.cmd_add_stack, 'delete': cli.cmd_delete_stack} if command not in commands: if os.path.exists(command): args = ['-t', command] + args command = 'info' else: if command.startswith('-'): print("First argument must be name of a command: %s" % command) else: print("Error: unknown command: %s" % command) usage() return 1 workspace = get_workspace(args, os.getcwd(), config_filename=ROSINSTALL_FILENAME) result = commands[command](workspace, args) or 0 return result except KeyboardInterrupt: pass rosinstall-0.7.8/src/rosinstall/setupfiles.py000066400000000000000000000327371272067315000214550ustar00rootroot00000000000000# Software License Agreement (BSD License) # # 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 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 rosinstall.__version__ from rosinstall.helpers import ROSInstallException, get_ros_stack_path # template for catkin fuerte, not valid for Groovy and beyond, to be # removed once fuerte goes out of support CATKIN_CMAKE_TOPLEVEL = """# # TOPLEVEL cmakelists # cmake_minimum_required(VERSION 2.8) cmake_policy(SET CMP0003 NEW) cmake_policy(SET CMP0011 NEW) set(CMAKE_CXX_FLAGS_INIT "-Wall") enable_testing() include(${CMAKE_SOURCE_DIR}/workspace-config.cmake OPTIONAL) list(APPEND CMAKE_PREFIX_PATH ${CMAKE_BINARY_DIR} ${CMAKE_BINARY_DIR}/cmake) file(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/lib) file(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/bin) if (IS_DIRECTORY ${CMAKE_SOURCE_DIR}/catkin) message(STATUS "+++ catkin") set(CATKIN_BUILD_PROJECTS "ALL" CACHE STRING "List of projects to build, or ALL for all. Use to completely exclude certain projects from cmake traversal.") add_subdirectory(catkin) else() find_package(catkin) endif() catkin_workspace() """ SHELL_HEADER = """# THIS IS AN AUTO-GENERATED FILE # IT IS UNLIKELY YOU WANT TO EDIT THIS FILE BY HAND # IF YOU WANT TO CHANGE THE ROS ENVIRONMENT VARIABLES # USE THE rosinstall OR rosws TOOL INSTEAD. # Generator version: %s # see: http://www.ros.org/wiki/rosinstall """ % rosinstall.__version__.version def generate_catkin_cmake(path, catkinpp): with open(os.path.join(path, "CMakeLists.txt"), 'w') as cmake_file: cmake_file.write(CATKIN_CMAKE_TOPLEVEL) if catkinpp: with open(os.path.join(path, "workspace-config.cmake"), 'w') as config_file: config_file.write("set (CMAKE_PREFIX_PATH %s)" % catkinpp) def generate_embedded_python(): return """import sys import os import yaml workspace_path = os.environ.get('ROS_WORKSPACE', os.path.abspath('.')) filename = os.path.join(workspace_path, '.rosinstall') if not os.path.isfile(filename): print('ERROR') sys.exit("There is no file at %s" % filename) with open(filename, "r") as fhand: try: v = fhand.read(); except Exception as e: print('ERROR') sys.exit("Failed to read file: %s %s " % (filename, str(e))) try: y = yaml.load(v); except Exception as e: print('ERROR') sys.exit("Invalid yaml in %s: %s " % (filename, str(e))) if y is not None: # put all non-setupfile entries into ROS_PACKAGE_PATH paths = [] for vdict in y: for k, v in vdict.items(): if v is not None and k != "setup-file": path = os.path.join(workspace_path, v['local-name']) if not os.path.isfile(path): # add absolute path from workspace to relative paths paths.append(os.path.normpath(path)) else: print('ERROR') sys.exit("ERROR: referenced path is a file, not a folder: %s" % path) output = '' # add paths in reverse order if len(paths) > 0: output += ':'.join(reversed(paths)) # We also want to return the location of any setupfile elements output += 'ROSINSTALL_PATH_SETUPFILE_SEPARATOR' setupfile_paths = [] for vdict in y: for k, v in vdict.items(): if v is not None and k == "setup-file": path = os.path.join(workspace_path, v['local-name']) if not os.path.exists(path): print('ERROR') sys.exit("WARNING: referenced setupfile does not exist: %s" % path) elif os.path.isfile(path): setupfile_paths.append(path) else: print('ERROR') sys.exit("ERROR: referenced setupfile is a folder: %s" % path) output += ':'.join(setupfile_paths) # printing will store the result in the variable print(output)""" def generate_setup_sh_text(workspacepath): ''' generates the string that goes into setup.sh. Sadly we cannot infer the workspacepath from within the sourced file, previous hacks trying to determine it from the shell context all failed in corner cases. :param workspacepath: The path to the workspace ''' pycode = generate_embedded_python() # overlay or standard text = """#!/usr/bin/env sh %(header)s # This setup.sh file has to parse .rosinstall file, and source similar # setup.sh files recursively. In the course of recursion, shell # variables get overwritten. This means that when returning from # recursion, any variable may be in a different state # These variables accumulate data through recursion and must only be # reset and unset at the top level of recursion. if [ x"$_ROSINSTALL_IN_RECURSION" != x"recurse" ] ; then # reset setupfile accumulator _SETUPFILES_ROSINSTALL= _ROS_PACKAGE_PATH_ROSINSTALL= # reset RPP before sourcing other setup files export ROS_PACKAGE_PATH= fi export ROS_WORKSPACE=%(wspath)s if [ ! "$ROS_MASTER_URI" ] ; then export ROS_MASTER_URI=http://localhost:11311 ; fi unset ROS_ROOT unset _SETUP_SH_ERROR # python script to read .rosinstall even when rosinstall is not installed # this files parses the .rosinstall and sets environment variables accordingly # The ROS_PACKAGE_PATH contains all elements in reversed order (for historic reasons) # We store into _PARSED_CONFIG the result of python code, # which is the ros_package_path and the list of setup_files to source # Using python here to benefit of the pyyaml library export _PARSED_CONFIG=`/usr/bin/env python << EOPYTHON %(pycode)s EOPYTHON` if [ x"$_PARSED_CONFIG" = x"ERROR" ]; then echo 'Could not parse .rosinstall file' 1<&2 _SETUP_SH_ERROR=1 fi # using sed to split up ros_package_path and setupfile results _ROS_PACKAGE_PATH_ROSINSTALL_NEW=`echo "$_PARSED_CONFIG" | sed 's,\(.*\)ROSINSTALL_PATH_SETUPFILE_SEPARATOR\(.*\),\\1,'` if [ ! -z "$_ROS_PACKAGE_PATH_ROSINSTALL_NEW" ]; then if [ ! -z "$_ROS_PACKAGE_PATH_ROSINSTALL" ]; then export _ROS_PACKAGE_PATH_ROSINSTALL=$_ROS_PACKAGE_PATH_ROSINSTALL:$_ROS_PACKAGE_PATH_ROSINSTALL_NEW else export _ROS_PACKAGE_PATH_ROSINSTALL=$_ROS_PACKAGE_PATH_ROSINSTALL_NEW fi fi _SETUPFILES_ROSINSTALL_NEW=`echo "$_PARSED_CONFIG" | sed 's,\(.*\)'ROSINSTALL_PATH_SETUPFILE_SEPARATOR'\(.*\),\\2,'` if [ ! -z "$_SETUPFILES_ROSINSTALL_NEW" ]; then if [ ! -z "$_SETUPFILES_ROSINSTALL" ]; then _SETUPFILES_ROSINSTALL=$_SETUPFILES_ROSINSTALL_NEW:$_SETUPFILES_ROSINSTALL else _SETUPFILES_ROSINSTALL=$_SETUPFILES_ROSINSTALL_NEW fi fi unset _PARSED_CONFIG # colon separates entries _LOOP_SETUP_FILE=`echo $_SETUPFILES_ROSINSTALL | sed 's,\([^:]*\)[:]\(.*\),\\1,'` # this loop does fake recursion, as the called setup.sh may work on # the remaining elements in the _SETUPFILES_ROSINSTALL stack while [ ! -z "$_LOOP_SETUP_FILE" ] do # need to pop from stack before recursing, as chained setup.sh might rely on this _SETUPFILES_ROSINSTALL=`echo $_SETUPFILES_ROSINSTALL | sed 's,\([^:]*[:]*\),,'` if [ -f "$_LOOP_SETUP_FILE" ]; then _ROSINSTALL_IN_RECURSION=recurse . $_LOOP_SETUP_FILE unset _ROSINSTALL_IN_RECURSION else echo warn: no such file : "$_LOOP_SETUP_FILE" fi _LOOP_SETUP_FILE=`echo $_SETUPFILES_ROSINSTALL | sed 's,\([^:]*\)[:]\(.*\),\\1,'` done unset _LOOP_SETUP_FILE unset _SETUPFILES_ROSINSTALL # prepend elements from .rosinstall file to ROS_PACKAGE_PATH # ignoring duplicates entries from value set by setup files export ROS_PACKAGE_PATH=`/usr/bin/env python << EOPYTHON import os ros_package_path = os.environ.get('ROS_PACKAGE_PATH', '') original_elements = ros_package_path.split(':') ros_package_path2 = os.environ.get('_ROS_PACKAGE_PATH_ROSINSTALL', '') new_elements = ros_package_path2.split(':') new_elements = [path for path in new_elements if path] for original_path in original_elements: if original_path and original_path not in new_elements: new_elements.append(original_path) print(':'.join(new_elements)) EOPYTHON` unset _ROS_PACKAGE_PATH_ROSINSTALL # restore ROS_WORKSPACE in case other setup.sh changed/unset it export ROS_WORKSPACE=%(wspath)s # if setup.sh did not set ROS_ROOT (pre-fuerte) if [ -z "${ROS_ROOT}" ]; then # using ROS_ROOT now being in ROS_PACKAGE_PATH export _ROS_ROOT_ROSINSTALL=`/usr/bin/env python << EOPYTHON import sys, os; if 'ROS_PACKAGE_PATH' in os.environ: pkg_path = os.environ['ROS_PACKAGE_PATH'] for path in pkg_path.split(':'): if (os.path.basename(path) == 'ros' and os.path.isfile(os.path.join(path, 'stack.xml'))): print(path) break EOPYTHON` if [ ! -z "${_ROS_ROOT_ROSINSTALL}" ]; then export ROS_ROOT=$_ROS_ROOT_ROSINSTALL export PATH=$ROS_ROOT/bin:$PATH export PYTHONPATH=$ROS_ROOT/core/roslib/src:$PYTHONPATH fi unset _ROS_ROOT_ROSINSTALL fi if [ ! -z "$_SETUP_SH_ERROR" ]; then # return failure code when sourcing file false fi """ % {'header': SHELL_HEADER, 'wspath': workspacepath, 'pycode': pycode} return text def generate_setup_bash_text(shell): ''' Generates the contents that go into a setup.bash or setup.zsh file. The intent of such a file is to enable shell extensions, such as special ros commands and tab completion. The generation is complex because the setup of the system changed between ROS electric and fuerte. In fuerte, the distro setup.sh also loads distro rosbash based on CATKIN_SHELL. Before fuerte, it is up to setup.bash to do so. ''' if shell == 'bash': script_path = """ SCRIPT_PATH="${BASH_SOURCE[0]}"; if([ -h "${SCRIPT_PATH}" ]) then while([ -h "${SCRIPT_PATH}" ]) do SCRIPT_PATH=`readlink "${SCRIPT_PATH}"`; done fi export OLDPWDBAK=$OLDPWD pushd . > /dev/null cd `dirname ${SCRIPT_PATH}` > /dev/null SCRIPT_PATH=`pwd`; popd > /dev/null export OLDPWD=$OLDPWDBAK """ call_setup_sh = ". $SCRIPT_PATH/setup.sh" elif shell == 'zsh': script_path = 'SCRIPT_PATH="$(dirname $0)"' call_setup_sh = """ emulate sh # emulate POSIX . $SCRIPT_PATH/setup.sh emulate zsh # back in zsh """ else: raise ROSInstallException("%s shell unsupported." % shell) text = """#!/usr/bin/env %(shell)s %(header)s CATKIN_SHELL=%(shell)s %(script_path)s # Load the path of this particular setup.%(shell)s if [ ! -f "$SCRIPT_PATH/setup.sh" ]; then echo "Bug: shell script unable to determine its own location: $SCRIPT_PATH" return 22 fi # unset _ros_decode_path (function of rosbash) to check later whether setup.sh has sourced ros%(shell)s unset -f _ros_decode_path 1> /dev/null 2>&1 %(call_setup_sh)s # if we have a ROS_ROOT, then we might need to source rosbash (pre-fuerte) if [ ! -z "${ROS_ROOT}" ]; then # check whether setup.sh also already sourced rosbash # Cannot rely on $? due to set -o errexit in build scripts RETURNCODE=`type _ros_decode_path 2> /dev/null | grep function 1>/dev/null 2>&1 || echo error` # for ROS electric and before, source rosbash if [ ! "$RETURNCODE" = "" ]; then RETURNCODE=`rospack help 1> /dev/null 2>&1 || echo error` if [ "$RETURNCODE" = "" ]; then ROSSHELL_PATH=`rospack find rosbash`/ros%(shell)s if [ -e "$ROSSHELL_PATH" ]; then . $ROSSHELL_PATH fi else echo "rospack could not be found, you cannot have ros%(shell)s features until you bootstrap ros" fi fi fi """ % {'shell': shell, 'script_path': script_path, 'call_setup_sh': call_setup_sh, 'header': SHELL_HEADER} return text def generate_setup(config, no_ros_allowed=False): ros_root = get_ros_stack_path(config) if ros_root is None: if not no_ros_allowed: candidates = [] for t in config.get_config_elements(): if os.path.basename(t.get_local_name()) == 'ros': candidates.append(t.get_path()) raise ROSInstallException(""" No 'ros' stack detected in candidates %s. Please add the location of a ros distribution to this command. See http://ros.org/wiki/rosinstall.""" % (candidates)) text = generate_setup_sh_text(workspacepath=config.get_base_path()) setup_path = os.path.join(config.get_base_path(), 'setup.sh') with open(setup_path, 'w') as fhand: fhand.write(text) for shell in ['bash', 'zsh']: text = generate_setup_bash_text(shell) setup_path = os.path.join(config.get_base_path(), 'setup.%s' % shell) with open(setup_path, 'w') as fhand: fhand.write(text) rosinstall-0.7.8/src/rosinstall/simple_checkout.py000066400000000000000000000045401272067315000224370ustar00rootroot00000000000000# Software License Agreement (BSD License) # # 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 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 sys import vcstools from wstool.config_yaml import get_path_spec_from_yaml def checkout_rosinstall(rosinstall_data, verbose=False): """ :param rosinstall_data: yaml dict in rosinstall format :raises: rosinstall.common.MultiProjectException for incvalid yaml """ for frag in rosinstall_data: path_spec = get_path_spec_from_yaml(frag) if verbose: print(path_spec.get_scmtype(), path_spec.get_path(), path_spec.get_uri(), path_spec.get_version()) vcs_client = vcstools.get_vcs_client(path_spec.get_scmtype(), path_spec.get_path()) vcs_client.checkout(path_spec.get_uri(), path_spec.get_version()) rosinstall-0.7.8/stdeb.cfg000066400000000000000000000010021272067315000154760ustar00rootroot00000000000000[DEFAULT] Depends: subversion, mercurial, git-core, bzr, python-yaml, python-vcstools (>= 0.1.38), python-catkin-pkg, python-rosdistro (>=0.3.0), python-wstool (>=0.1.12) Depends3: subversion, mercurial, git-core, bzr, python3-yaml, python3-vcstools (>= 0.1.38), python3-catkin-pkg, python3-rosdistro (>=0.3.0), python3-wstool (>=0.1.12) Conflicts: python3-rosinstall Conflicts3: python-rosinstall Suite: oneiric precise quantal raring saucy trusty utopic vivid wily xenial wheezy jessie X-Python3-Version: >= 3.2 rosinstall-0.7.8/test/000077500000000000000000000000001272067315000147025ustar00rootroot00000000000000rosinstall-0.7.8/test/__init__.py000066400000000000000000000000001272067315000170010ustar00rootroot00000000000000rosinstall-0.7.8/test/example-broken.yaml000066400000000000000000000000261272067315000204750ustar00rootroot00000000000000text foobar number: 2 rosinstall-0.7.8/test/example_dirs/000077500000000000000000000000001272067315000173565ustar00rootroot00000000000000rosinstall-0.7.8/test/example_dirs/ros/000077500000000000000000000000001272067315000201615ustar00rootroot00000000000000rosinstall-0.7.8/test/example_dirs/ros/stack.xml000066400000000000000000000000001272067315000217760ustar00rootroot00000000000000rosinstall-0.7.8/test/example_dirs/ros_comm/000077500000000000000000000000001272067315000211745ustar00rootroot00000000000000rosinstall-0.7.8/test/example_dirs/ros_comm/stack.xml000066400000000000000000000000001272067315000230110ustar00rootroot00000000000000rosinstall-0.7.8/test/example_dirs/roscpp/000077500000000000000000000000001272067315000206645ustar00rootroot00000000000000rosinstall-0.7.8/test/example_dirs/roscpp/manifest.xml000066400000000000000000000000001272067315000232020ustar00rootroot00000000000000rosinstall-0.7.8/test/io_wrapper.py000066400000000000000000000006061272067315000174250ustar00rootroot00000000000000class StringIO: """ StringIO.StringIO does not exist in python3 io.StringIO cannot cope with unicode """ def __init__(self): self.stream = '' def write(self, data): self.stream += data def flush(self): pass def __getattr__(self, attr): return getattr(self.stream, attr) def getvalue(self): return self.stream rosinstall-0.7.8/test/local/000077500000000000000000000000001272067315000157745ustar00rootroot00000000000000rosinstall-0.7.8/test/local/__init__.py000066400000000000000000000000001272067315000200730ustar00rootroot00000000000000rosinstall-0.7.8/test/local/test_locate.py000066400000000000000000000230301272067315000206520ustar00rootroot00000000000000import unittest from mock import Mock import rosinstall.locate as locate class LocateTest(unittest.TestCase): def test_getters_invalid(self): data = { 'vcs': None, 'vcs_uri': None} self.assertRaises(locate.InvalidData, locate.get_rosinstall, 'myname', data, None) data = { 'vcs': None, 'vcs_uri': 'https://code.ros.org/svn/ros-pkg'} self.assertRaises(locate.InvalidData, locate.get_rosinstall, 'myname', data, None) data = { 'vcs': 'svn', 'vcs_uri': None} self.assertRaises(locate.InvalidData, locate.get_rosinstall, 'myname', data, None) data = {} self.assertRaises(locate.InvalidData, locate.get_rosinstall, 'myname', data, None) data = {'vcs_uri': 'https://code.ros.org/svn/ros-pkg'} self.assertRaises(locate.InvalidData, locate.get_rosinstall, 'myname', data, None) data = {'vcs': 'svn'} self.assertRaises(locate.InvalidData, locate.get_rosinstall, 'myname', data, None) data = {'rosinstalls': None} self.assertRaises(locate.InvalidData, locate.get_rosinstall, 'myname', data, 'mytype', 'devel') data = {'rosinstall': None} self.assertRaises(locate.InvalidData, locate.get_rosinstall, 'myname', data, 'mytype', None) def test_getters_empty(self): data = {'vcs': 'svn', 'vcs_uri': 'https://code.ros.org/svn/ros-pkg'} self.assertEqual('', locate.get_www(None, data, None)) self.assertEqual('', locate.get_repo(None, data, None)) self.assertEqual('https://code.ros.org/svn/ros-pkg', locate.get_vcs_uri_for_branch(data)) self.assertEqual('https://code.ros.org/svn/ros-pkg', locate.get_vcs_uri_for_branch(data, 'release')) self.assertEqual('https://code.ros.org/svn/ros-pkg', locate.get_vcs_uri_for_branch(data, 'devel')) self.assertEqual('svn', locate.get_vcs(None, data, None)) self.assertEqual('- svn:\n local-name: myname\n uri: https://code.ros.org/svn/ros-pkg\n', locate.get_rosinstall('myname', data, 'mytype')) self.assertEqual('- svn:\n local-name: myname\n uri: https://code.ros.org/svn/ros-pkg\n', locate.get_rosinstall('myname', data, 'mytype', 'devel')) self.assertEqual('- svn:\n local-name: myname\n uri: https://code.ros.org/svn/ros-pkg\n', locate.get_rosinstall('myname', data, 'mytype', 'release')) self.assertEqual('- svn:\n local-name: foo/myname\n uri: https://code.ros.org/svn/ros-pkg\n', locate.get_rosinstall('myname', data, 'mytype', None, 'foo')) self.assertEqual('https://code.ros.org/svn/ros-pkg', locate.get_vcs_uri(data)) self.assertEqual('', locate.get_vcs_version(data)) self.assertEqual('package', locate.get_type(data)) def test_get_with_branches(self): data = { 'rosinstalls': {'devel': {'hg': {'local-name': 'navigation', 'uri': 'https://kforge.ros.org/test/devel', 'version': 'navigation-1.6'}}, 'distro': {'hg': {'local-name': 'navigation', 'uri': 'https://kforge.ros.org/test/distro', 'version': 'electric'}}, 'release': {'hg': {'local-name': 'navigation', 'uri': 'https://kforge.ros.org/test/rel', 'version': 'navigation-1.6.5'}}}, 'vcs': 'svn', 'vcs_uri': 'https://code.ros.org/svn/ros-pkg'} self.assertEqual('https://code.ros.org/svn/ros-pkg', locate.get_vcs_uri_for_branch(data)) self.assertEqual('https://kforge.ros.org/test/rel', locate.get_vcs_uri_for_branch(data, 'release')) self.assertEqual('https://kforge.ros.org/test/devel', locate.get_vcs_uri_for_branch(data, 'devel')) self.assertEqual('https://kforge.ros.org/test/distro', locate.get_vcs_uri_for_branch(data, 'distro')) self.assertEqual('svn', locate.get_vcs(None, data, None)) self.assertEqual('https://code.ros.org/svn/ros-pkg', locate.get_vcs_uri(data)) self.assertEqual('', locate.get_vcs_version(data)) self.assertEqual('package', locate.get_type(data)) self.assertEqual( '- svn:\n local-name: myname\n uri: https://code.ros.org/svn/ros-pkg\n', locate.get_rosinstall('myname', data, 'mytype')) self.assertEqual( '- hg:\n local-name: navigation\n uri: https://kforge.ros.org/test/devel\n version: navigation-1.6\n', locate.get_rosinstall('myname', data, 'mytype', 'devel')) self.assertEqual( '- hg:\n local-name: navigation\n uri: https://kforge.ros.org/test/rel\n version: navigation-1.6.5\n', locate.get_rosinstall('myname', data, 'mytype', 'release')) self.assertEqual( '- svn:\n local-name: foo/myname\n uri: https://code.ros.org/svn/ros-pkg\n', locate.get_rosinstall('myname', data, 'mytype', None, 'foo')) def test_get_with_rosinstall(self): data = { 'rosinstall': {'hg': {'local-name': 'navigation', 'uri': 'https://kforge.ros.org/test/rel', 'version': 'navigation-1.6.5'}}, 'vcs': 'svn', 'vcs_uri': 'https://code.ros.org/svn/ros-pkg'} self.assertEqual( '- hg:\n local-name: navigation\n uri: https://kforge.ros.org/test/rel\n version: navigation-1.6.5\n', locate.get_rosinstall('myname', data, 'mytype')) self.assertEqual( '- hg:\n local-name: foo/navigation\n uri: https://kforge.ros.org/test/rel\n version: navigation-1.6.5\n', locate.get_rosinstall('myname', data, 'mytype', None, 'foo')) def test_getters(self): data = {'package_type': 'package', 'repo_name': 'visualization', 'repo_url': '', 'srvs': [], 'timestamp': 1362233859.0088351, 'url': 'http://ros.org/wiki/rviz', 'vcs': 'svn', 'vcs_uri': 'https://code.ros.org/svn/ros-pkg', 'vcs_version': '0.1', 'repository': 'navigation'} self.assertEqual('http://ros.org/wiki/rviz', locate.get_www(None, data, None)) self.assertEqual('visualization', locate.get_repo(None, data, None)) self.assertEqual( '- svn:\n local-name: foo/myname\n uri: https://code.ros.org/svn/ros-pkg\n version: \'0.1\'\n', locate.get_rosinstall('myname', data, 'mytype', None, 'foo')) self.assertEqual('https://code.ros.org/svn/ros-pkg', locate.get_vcs_uri(data)) self.assertEqual('0.1', locate.get_vcs_version(data)) self.assertEqual('package', locate.get_type(data)) def test_get_manifest_groovy(self): distro = 'groovy' # rviz result = locate.get_manifest('rviz', distro) self.assertEqual('package', result[1], result) # rospack (data, type_, url) = locate.get_manifest('rospack', distro) self.assertEqual('package', type_) data = locate._get_rosinstall_dict('rospack', data, type_) self.assertEqual('https://github.com/ros/rospack.git', data.get('git', {}).get('uri', '')) self.assertTrue(distro in data.get('git', {}).get('version', ''), data) # ros_comm (data, type_, url) = locate.get_manifest('ros_comm', distro) self.assertEqual('metapackage', type_) data = locate._get_rosinstall_dict('ros_comm', data, type_) self.assertEqual('https://github.com/ros/ros_comm.git', data.get('git', {}).get('uri', '')) self.assertTrue(distro in data.get('git', {}).get('version', ''), data) def test_get_manifest_current(self): # this test obviously returns different results over time distro = None # rviz result = locate.get_manifest('rviz', distro) self.assertEqual('package', result[1], result) # rospack (data, type_, url) = locate.get_manifest('rospack', distro) self.assertEqual('package', type_) data = locate._get_rosinstall_dict('rospack', data, type_) self.assertEqual('https://github.com/ros/rospack.git', data.get('git', {}).get('uri', '')) # ros_comm (data, type_, url) = locate.get_manifest('ros_comm', distro) self.assertEqual('metapackage', type_) data = locate._get_rosinstall_dict('ros_comm', data, type_) self.assertEqual('https://github.com/ros/ros_comm.git', data.get('git', {}).get('uri', '')) rosinstall-0.7.8/test/local/test_ros_cli.py000066400000000000000000000471741272067315000210540ustar00rootroot00000000000000#!/usr/bin/env python # Software License Agreement (BSD License) # # 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 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 subprocess import shutil import rosinstall.rosws_cli from test.scm_test_base import AbstractFakeRosBasedTest, _create_yaml_file, _create_config_elt_dict from wstool.config_yaml import PathSpec import wstool.multiproject_cmd from rosinstall.rosws_cli import RoswsCLI from rosinstall.helpers import ROSInstallException class FakeConfig(): def __init__(self, elts=[], celts=[], basepath=''): self.elts = elts self.celts = celts self.basepath = basepath def get_config_elements(self): return self.celts def get_source(self): return self.elts def get_base_path(self): return self.basepath class MockConfigElement(): def __init__(self, local_name='', scmtype=None, path=None, uri=None, spec=None): self.scmtype = scmtype self.path = path self.uri = uri self.local_name = local_name self.spec = spec def get_path(self): return self.path def get_local_name(self): return self.local_name def get_path_spec(self): return self.spec def is_vcs_element(self): return True if self.scmtype else False class RosinstallCommandlineTest(AbstractFakeRosBasedTest): def test_require_bootstrap(self): config = FakeConfig() self.assertFalse(rosinstall.rosinstall_cmd._ros_requires_boostrap(config)) config = FakeConfig([PathSpec(self.ros_path, path=self.ros_path)]) self.assertFalse(rosinstall.rosinstall_cmd._ros_requires_boostrap(config)) config = FakeConfig([PathSpec(self.ros_path, 'git', 'gituri', path=self.ros_path)]) self.assertTrue(rosinstall.rosinstall_cmd._ros_requires_boostrap(config)) class RosinstallCommandLineGenerationTest(AbstractFakeRosBasedTest): def test_cmd_generate_ros_files_simple(self): self.local_path = os.path.join(self.test_root_path, "ws") os.makedirs(self.local_path) config = FakeConfig(celts=[MockConfigElement(path=self.ros_path)], basepath=self.local_path) rosinstall.rosinstall_cmd.cmd_generate_ros_files(config, self.local_path, nobuild=True, rosdep_yes=False, catkin=False, catkinpp=None) self.assertTrue(os.path.exists(os.path.join(self.local_path, 'setup.sh'))) self.assertTrue(os.path.exists(os.path.join(self.local_path, 'setup.bash'))) self.assertTrue(os.path.exists(os.path.join(self.local_path, 'setup.zsh'))) def test_cmd_generate_ros_files_vcs(self): self.local_path = os.path.join(self.test_root_path, "ws2") os.makedirs(self.local_path) config = FakeConfig(celts=[MockConfigElement(path=self.ros_path), MockConfigElement(path='gitrepo', scmtype='git', uri=self.git_path), MockConfigElement(path='hgrepo', scmtype='hg', uri=self.hg_path)], basepath=self.local_path) rosinstall.rosinstall_cmd.cmd_generate_ros_files(config, self.local_path, nobuild=True, rosdep_yes=False, catkin=False, catkinpp=None) self.assertTrue(os.path.exists(os.path.join(self.local_path, 'setup.sh'))) self.assertTrue(os.path.exists(os.path.join(self.local_path, 'setup.bash'))) self.assertTrue(os.path.exists(os.path.join(self.local_path, 'setup.zsh'))) def test_cmd_generate_ros_files_catkin(self): self.local_path = os.path.join(self.test_root_path, "ws3") os.makedirs(self.local_path) config = FakeConfig([PathSpec(self.ros_path), PathSpec('gitrepo', 'git', uri=self.git_path)], self.local_path) rosinstall.rosinstall_cmd.cmd_generate_ros_files(config, self.local_path, nobuild=True, rosdep_yes=False, catkin=True, catkinpp=False) self.assertFalse(os.path.exists(os.path.join(self.local_path, 'setup.sh'))) self.assertFalse(os.path.exists(os.path.join(self.local_path, 'setup.bash'))) self.assertFalse(os.path.exists(os.path.join(self.local_path, 'setup.zsh'))) self.assertTrue(os.path.exists(os.path.join(self.local_path, 'CMakeLists.txt'))) def test_cmd_generate_ros_files_catkinpp(self): self.local_path = os.path.join(self.test_root_path, "ws4") os.makedirs(self.local_path) config = FakeConfig([PathSpec(self.ros_path), PathSpec('gitrepo', 'git', uri=self.git_path)], self.local_path) rosinstall.rosinstall_cmd.cmd_generate_ros_files(config, self.local_path, nobuild=True, rosdep_yes=False, catkin=True, catkinpp=True) self.assertFalse(os.path.exists(os.path.join(self.local_path, 'setup.sh'))) self.assertFalse(os.path.exists(os.path.join(self.local_path, 'setup.bash'))) self.assertFalse(os.path.exists(os.path.join(self.local_path, 'setup.zsh'))) self.assertTrue(os.path.exists(os.path.join(self.local_path, 'CMakeLists.txt'))) self.assertTrue(os.path.exists(os.path.join(self.local_path, 'workspace-config.cmake'))) def test_cmd_generate_ros_files_build(self): self.local_path = os.path.join(self.test_root_path, "ws2b") os.makedirs(self.local_path) local_rosinstall = os.path.join(self.test_root_path, "local.rosinstall") _create_yaml_file([_create_config_elt_dict("git", 'ros_comm', self.git_path), _create_config_elt_dict("git", 'ros', self.ros_path), _create_config_elt_dict("hg", 'hgrepo', self.hg_path)], local_rosinstall) cli = RoswsCLI() self.assertEqual(0, cli.cmd_init([self.local_path, local_rosinstall])) self.assertTrue(os.path.exists(os.path.join(self.local_path, 'setup.sh'))) self.assertTrue(os.path.exists(os.path.join(self.local_path, 'setup.bash'))) self.assertTrue(os.path.exists(os.path.join(self.local_path, 'setup.zsh'))) def test_cmd_init(self): self.local_path = os.path.join(self.test_root_path, "ws5") os.makedirs(self.local_path) cli = RoswsCLI() self.assertEqual(0, cli.cmd_init([self.local_path, self.ros_path])) self.assertTrue(os.path.exists(os.path.join(self.local_path, 'setup.sh'))) self.assertTrue(os.path.exists(os.path.join(self.local_path, 'setup.bash'))) self.assertTrue(os.path.exists(os.path.join(self.local_path, 'setup.zsh'))) self.assertTrue(os.path.exists(os.path.join(self.local_path, '.rosinstall'))) self.assertEqual(0, subprocess.call(". %s" % os.path.join(self.local_path, 'setup.sh'), shell=True, env=self.new_environ)) self.assertEqual(0, subprocess.call(". %s" % os.path.join(self.local_path, 'setup.bash'), shell=True, env=self.new_environ, executable='/bin/bash')) self.assertEqual(0, cli.cmd_merge(self.local_path, [self.ros_path, "-y"])) self.assertTrue(os.path.exists(os.path.join(self.local_path, 'setup.sh'))) self.assertTrue(os.path.exists(os.path.join(self.local_path, 'setup.bash'))) self.assertTrue(os.path.exists(os.path.join(self.local_path, 'setup.zsh'))) self.assertTrue(os.path.exists(os.path.join(self.local_path, '.rosinstall'))) self.assertEqual(0, subprocess.call(". %s" % os.path.join(self.local_path, 'setup.sh'), shell=True, env=self.new_environ)) self.assertEqual(0, subprocess.call(". %s" % os.path.join(self.local_path, 'setup.bash'), shell=True, env=self.new_environ, executable='/bin/bash')) def test_cmd_init_catkin(self): self.local_path = os.path.join(self.test_root_path, "ws6") os.makedirs(self.local_path) cli = RoswsCLI() self.assertEqual(0, cli.cmd_init([self.local_path, self.ros_path, "-c"])) self.assertFalse(os.path.exists(os.path.join(self.local_path, 'setup.sh'))) self.assertFalse(os.path.exists(os.path.join(self.local_path, 'setup.bash'))) self.assertFalse(os.path.exists(os.path.join(self.local_path, 'setup.zsh'))) self.assertTrue(os.path.exists(os.path.join(self.local_path, '.rosinstall'))) self.assertTrue(os.path.exists(os.path.join(self.local_path, 'CMakeLists.txt'))) def test_cmd_init_catkin2(self): self.local_path = os.path.join(self.test_root_path, "ws7") os.makedirs(self.local_path) cli = RoswsCLI() self.assertEqual(0, cli.cmd_init([self.local_path, self.ros_path, "--catkin"])) self.assertFalse(os.path.exists(os.path.join(self.local_path, 'setup.sh'))) self.assertFalse(os.path.exists(os.path.join(self.local_path, 'setup.bash'))) self.assertFalse(os.path.exists(os.path.join(self.local_path, 'setup.zsh'))) self.assertTrue(os.path.exists(os.path.join(self.local_path, '.rosinstall'))) self.assertTrue(os.path.exists(os.path.join(self.local_path, 'CMakeLists.txt'))) def test_cmd_init_catkinpp(self): self.local_path = os.path.join(self.test_root_path, "ws8") os.makedirs(self.local_path) cli = RoswsCLI() self.assertEqual(0, cli.cmd_init([self.local_path, self.ros_path, "--catkin", "--cmake-prefix-path=foo"])) self.assertFalse(os.path.exists(os.path.join(self.local_path, 'setup.sh'))) self.assertFalse(os.path.exists(os.path.join(self.local_path, 'setup.bash'))) self.assertFalse(os.path.exists(os.path.join(self.local_path, 'setup.zsh'))) self.assertTrue(os.path.exists(os.path.join(self.local_path, '.rosinstall'))) self.assertTrue(os.path.exists(os.path.join(self.local_path, 'CMakeLists.txt'))) self.assertTrue(os.path.exists(os.path.join(self.local_path, 'workspace-config.cmake'))) def test_cmd_init_makedir(self): # rosinstall to create dir self.local_path = os.path.join(self.test_root_path, "ws9") cli = RoswsCLI() self.assertEqual(0, cli.cmd_init([self.local_path, self.ros_path])) self.assertTrue(os.path.exists(os.path.join(self.local_path, 'setup.sh'))) self.assertTrue(os.path.exists(os.path.join(self.local_path, 'setup.bash'))) self.assertTrue(os.path.exists(os.path.join(self.local_path, 'setup.zsh'))) def test_cmd_init_no_ros(self): self.local_path = os.path.join(self.test_root_path, "ws10") ros_root_existed = False if 'ROS_ROOT' in os.environ: ros_root_existed = True oldros = os.environ.pop('ROS_ROOT') cli = RoswsCLI() self.assertEqual(0, cli.cmd_init([self.local_path])) shutil.rmtree(self.local_path) os.environ['ROS_ROOT'] = self.ros_path self.assertEqual(0, cli.cmd_init([self.local_path])) self.assertTrue(os.path.exists(os.path.join(self.local_path, 'setup.sh'))) self.assertTrue(os.path.exists(os.path.join(self.local_path, 'setup.bash'))) self.assertTrue(os.path.exists(os.path.join(self.local_path, 'setup.zsh'))) if ros_root_existed: os.environ['ROS_ROOT'] = oldros else: os.environ.pop('ROS_ROOT') def test_cmd_init_main(self): # rosinstall to create dir ros_root_existed = False if 'ROS_ROOT' in os.environ: ros_root_existed = True oldros = os.environ.pop('ROS_ROOT') os.environ['ROS_ROOT'] = self.ros_path self.local_path = os.path.join(self.test_root_path, "ws11") self.assertEqual(0, rosinstall.rosws_cli.rosws_main(['rosws', 'help'])) self.assertEqual(0, rosinstall.rosws_cli.rosws_main(['rosws', 'init', self.local_path])) self.assertEqual(0, rosinstall.rosws_cli.rosws_main(['rosws', 'info', '-t', self.local_path])) self.assertEqual(0, rosinstall.rosws_cli.rosws_main(['rosws', 'info', '--pkg-path-only', '-t', self.local_path])) self.assertEqual(0, rosinstall.rosws_cli.rosws_main(['rosws', 'info', '--no-pkg-path', '-t', self.local_path])) self.assertEqual(0, rosinstall.rosws_cli.rosws_main(['rosws', 'info', '--data-only', '-t', self.local_path])) self.assertTrue(os.path.exists(os.path.join(self.local_path, 'setup.sh'))) self.assertTrue(os.path.exists(os.path.join(self.local_path, 'setup.bash'))) self.assertTrue(os.path.exists(os.path.join(self.local_path, 'setup.zsh'))) if ros_root_existed: os.environ['ROS_ROOT'] = oldros else: os.environ.pop('ROS_ROOT') def test_cmd_remove(self): # rosinstall to create dir self.local_path = os.path.join(self.test_root_path, "ws12") cli = RoswsCLI() self.assertEqual(0, cli.cmd_init([self.local_path, self.ros_path])) self.assertEqual(0, cli.cmd_merge(self.local_path, [self.git_path, "-y"])) self.assertEqual(0, cli.cmd_merge(self.local_path, [self.hg_path, "-y"])) config = wstool.multiproject_cmd.get_config(basepath=self.local_path, config_filename='.rosinstall') self.assertEqual(len(config.get_config_elements()), 3) self.assertEqual(0, cli.cmd_remove(self.local_path, [self.git_path])) config = wstool.multiproject_cmd.get_config(basepath=self.local_path, config_filename='.rosinstall') self.assertEqual(len(config.get_config_elements()), 2) def execute_check_result_allshells(self, command, path, cwd=None, expect=''): """sources in turn each setup.*sh and runs command""" # zsh has issues with SCRIPT_PATH for shell in ['sh', 'bash']: cmd = ". %s ; %s" % (os.path.join(path, 'setup.%s' % shell), command) p = subprocess.Popen(cmd, shell=True, cwd=cwd, stdout=subprocess.PIPE, executable='/bin/%s' % shell) output = p.communicate()[0] self.assertEqual(expect.encode('UTF-8'), output.strip(), ("'%s' != '%s', cmd: %s, cwd: %s" % (expect, output, cmd, cwd))) self.assertEqual(0, p.returncode) def test_init_parallel(self): self.local_path = os.path.join(self.test_root_path, "ws13a") cli = RoswsCLI() self.assertEqual(0, cli.cmd_init([self.local_path, self.simple_rosinstall, "--parallel=5"])) command = "echo $ROS_WORKSPACE" self.execute_check_result_allshells(command, self.local_path, expect=self.local_path) self.execute_check_result_allshells(command, '.', cwd=self.local_path, expect=self.local_path) self.execute_check_result_allshells(command, 'ws13a', cwd=self.test_root_path, expect=self.local_path) local_ros_path = os.path.join(self.local_path, "ros") local_git_path = os.path.join(self.local_path, "gitrepo") package_path = "%s:%s" % (local_git_path, local_ros_path) command = "echo $ROS_PACKAGE_PATH" self.execute_check_result_allshells(command, self.local_path, expect=package_path) self.execute_check_result_allshells(command, '.', cwd=self.local_path, expect=package_path) self.execute_check_result_allshells(command, 'ws13a', cwd=self.test_root_path, expect=package_path) def test_setup_sh(self): self.local_path = os.path.join(self.test_root_path, "ws13") cli = RoswsCLI() self.assertEqual(0, cli.cmd_init([self.local_path, self.simple_rosinstall])) command = "echo $ROS_WORKSPACE" self.execute_check_result_allshells(command, self.local_path, expect=self.local_path) self.execute_check_result_allshells(command, '.', cwd=self.local_path, expect=self.local_path) self.execute_check_result_allshells(command, 'ws13', cwd=self.test_root_path, expect=self.local_path) local_ros_path = os.path.join(self.local_path, "ros") local_git_path = os.path.join(self.local_path, "gitrepo") package_path = "%s:%s" % (local_git_path, local_ros_path) command = "echo $ROS_PACKAGE_PATH" self.execute_check_result_allshells(command, self.local_path, expect=package_path) self.execute_check_result_allshells(command, '.', cwd=self.local_path, expect=package_path) self.execute_check_result_allshells(command, 'ws13', cwd=self.test_root_path, expect=package_path) def test_setup_sh_relros(self): self.local_path = os.path.join(self.test_root_path, "ws14") cli = RoswsCLI() simple_rel_rosinstall = os.path.join(self.test_root_path, "simple_rel.rosinstall") _create_yaml_file([_create_config_elt_dict("git", "ros", "../ros")], simple_rel_rosinstall) self.assertEqual(0, cli.cmd_init([self.local_path, simple_rel_rosinstall])) command = "echo $ROS_WORKSPACE" self.execute_check_result_allshells(command, self.local_path, expect=self.local_path) self.execute_check_result_allshells(command, '.', cwd=self.local_path, expect=self.local_path) self.execute_check_result_allshells(command, 'ws14', cwd=self.test_root_path, expect=self.local_path) package_path = os.path.join(self.local_path, "ros") command = "echo $ROS_PACKAGE_PATH" self.execute_check_result_allshells(command, self.local_path, expect=package_path) self.execute_check_result_allshells(command, '.', cwd=self.local_path, expect=package_path) self.execute_check_result_allshells(command, 'ws14', cwd=self.test_root_path, expect=package_path) def test_setup_sh_relother(self): self.local_path = os.path.join(self.test_root_path, "ws15") cli = RoswsCLI() simple_rel_rosinstall = os.path.join(self.test_root_path, "simple_rel2.rosinstall") _create_yaml_file([_create_config_elt_dict("git", "ros", "../ros"), _create_config_elt_dict("other", "../gitrepo")], simple_rel_rosinstall) self.assertEqual(0, cli.cmd_init([self.local_path, simple_rel_rosinstall])) command = "echo $ROS_WORKSPACE" self.execute_check_result_allshells(command, self.local_path, expect=self.local_path) self.execute_check_result_allshells(command, '.', cwd=self.local_path, expect=self.local_path) self.execute_check_result_allshells(command, 'ws15', cwd=self.test_root_path, expect=self.local_path) local_ros_path = os.path.join(self.local_path, "ros") package_path = "%s:%s" % (self.git_path, local_ros_path) command = "echo $ROS_PACKAGE_PATH" self.execute_check_result_allshells(command, self.local_path, expect=package_path) self.execute_check_result_allshells(command, '.', cwd=self.local_path, expect=package_path) self.execute_check_result_allshells(command, 'ws15', cwd=self.test_root_path, expect=package_path) rosinstall-0.7.8/test/local/test_rosinstall.py000066400000000000000000000332721272067315000216060ustar00rootroot00000000000000# Software License Agreement (BSD License) # # 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 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 copy import yaml import subprocess import tempfile import rosinstall import rosinstall.helpers from rosinstall.rosinstall_cli import rosinstall_main from test.scm_test_base import AbstractRosinstallBaseDirTest, AbstractFakeRosBasedTest, _create_yaml_file, _create_config_elt_dict class RosinstallCommandlineOverlays(AbstractFakeRosBasedTest): """test creating parallel rosinstall env with overlayed stacks""" def setUp(self): """runs rosinstall with generated self.simple_rosinstall to create local rosinstall env and creates a directory for a second local rosinstall env""" AbstractFakeRosBasedTest.setUp(self) # setup a rosinstall env as base for further tests cmd = copy.copy(self.rosinstall_fn) cmd.extend([self.directory, self.simple_rosinstall]) self.assertTrue(rosinstall_main(cmd)) self.new_directory = tempfile.mkdtemp() self.directories["new_ros_env"] = self.new_directory def test_Rosinstall_rosinstall_file_input(self): """uses base rosinstall with ros and git repo""" cmd = copy.copy(self.rosinstall_fn) cmd.extend([self.new_directory, self.directory]) self.assertTrue(rosinstall_main(cmd)) stream = open(os.path.join(self.new_directory, '.rosinstall'), 'r') yamlsrc = yaml.load(stream) stream.close() self.assertEqual(2, len(yamlsrc)) self.assertEqual('other', list(yamlsrc[0].keys())[0]) self.assertEqual('other', list(yamlsrc[1].keys())[0]) def test_Rosinstall_rosinstall_file_input_ros_only(self): """uses base ros folder""" local_rosinstall = os.path.join(self.test_root_path, "local.rosinstall") # invalid recursion itno some other rosinstall folder _create_yaml_file([_create_config_elt_dict("other", self.directory)], local_rosinstall) cmd = copy.copy(self.rosinstall_fn) cmd.extend([self.new_directory, self.ros_path, local_rosinstall]) self.assertTrue(rosinstall_main(cmd)) stream = open(os.path.join(self.new_directory, '.rosinstall'), 'r') yamlsrc = yaml.load(stream) stream.close() self.assertEqual(1, len(yamlsrc)) self.assertEqual('other', list(yamlsrc[0].keys())[0]) def test_Rosinstall_rosinstall_file_input_add(self): """uses base ros folders and adds a stack""" local_rosinstall = os.path.join(self.test_root_path, "local2.rosinstall") # self.directory points invalidly at a folder containing a .rosinstall pointing to ros and gitrepo _create_yaml_file([_create_config_elt_dict("other", self.directory), _create_config_elt_dict("hg", "gitrepo", self.hg_path)], local_rosinstall) cmd = copy.copy(self.rosinstall_fn) cmd.extend([self.new_directory, self.ros_path, local_rosinstall]) self.assertTrue(rosinstall_main(cmd)) stream = open(os.path.join(self.new_directory, '.rosinstall'), 'r') yamlsrc = yaml.load(stream) stream.close() self.assertEqual(2, len(yamlsrc)) self.assertEqual('other', list(yamlsrc[0].keys())[0]) self.assertEqual('hg', list(yamlsrc[1].keys())[0]) def test_Rosinstall_ros_with_folder(self): """Use a folder as a remote rosinstall location""" cmd = copy.copy(self.rosinstall_fn) cmd.extend([self.new_directory, self.directory]) self.assertTrue(rosinstall_main(cmd)) class RosinstallCommandlineOverlaysWithSetup(AbstractFakeRosBasedTest): """test creating parallel rosinstall env with overlayed stacks""" def setUp(self): """runs rosinstall with generated self.simple_rosinstall to create local rosinstall env and creates a second directory self.new_directory for a second local rosinstall env""" AbstractFakeRosBasedTest.setUp(self) self.simple_fuerte_rosinstall = os.path.join(self.test_root_path, "simple_fuerte.rosinstall") _create_yaml_file([_create_config_elt_dict("git", "ros", self.ros_path), _create_config_elt_dict("setup-file", "setup.sh"), _create_config_elt_dict("hg", "hgrepo", self.hg_path)], self.simple_fuerte_rosinstall) # setup a rosinstall env as base for further tests cmd = copy.copy(self.rosinstall_fn) cmd.extend([self.directory, self.simple_fuerte_rosinstall]) self.assertTrue(rosinstall_main(cmd)) self.new_directory = tempfile.mkdtemp() self.directories["new_ros_env"] = self.new_directory def test_Rosinstall_rosinstall_file_input_with_setupfile(self): local_rosinstall = os.path.join(self.test_root_path, "local.rosinstall") _create_yaml_file([_create_config_elt_dict("other", self.directory), _create_config_elt_dict("hg", "hgrepo", self.hg_path)], local_rosinstall) cmd = copy.copy(self.rosinstall_fn) cmd.extend([self.new_directory, self.ros_path, local_rosinstall]) self.assertTrue(rosinstall_main(cmd)) stream = open(os.path.join(self.new_directory, '.rosinstall'), 'r') yamlsrc = yaml.load(stream) stream.close() self.assertEqual(2, len(yamlsrc), yamlsrc) self.assertEqual('other', list(yamlsrc[0].keys())[0]) # ros self.assertEqual('hg', list(yamlsrc[1].keys())[0]) # hg_repo def test_Rosinstall_ros_with_folder_and_setupfile(self): cmd = copy.copy(self.rosinstall_fn) cmd.extend([self.new_directory, self.directory]) self.assertTrue(rosinstall_main(cmd)) stream = open(os.path.join(self.new_directory, '.rosinstall'), 'r') yamlsrc = yaml.load(stream) stream.close() self.assertEqual(3, len(yamlsrc)) self.assertEqual('other', list(yamlsrc[0].keys())[0]) self.assertEqual('setup-file', list(yamlsrc[1].keys())[0]) self.assertEqual('other', list(yamlsrc[2].keys())[0]) class RosinstallLocalDistro(AbstractRosinstallBaseDirTest): def test_prereq(self): self.assertTrue(os.path.exists('/bin/bash')) self.assertTrue(os.path.exists('/bin/zsh')) if os.path.isdir('/opt/ros/cturtle'): def test_local_cturtle(self): distrodir = '/opt/ros/cturtle' cmd = copy.copy(self.rosinstall_fn) cmd.extend([self.directory, distrodir]) self.assertTrue(rosinstall_main(cmd)) self.assertEqual(0, subprocess.call(". %s" % os.path.join(self.directory, 'setup.sh'), shell=True, env=self.new_environ)) self.assertEqual(0, subprocess.call(". %s" % os.path.join(self.directory, 'setup.bash'), shell=True, env=self.new_environ, executable='/bin/bash')) if os.path.isdir('/opt/ros/diamondback'): def test_local_diamondback(self): distrodir = '/opt/ros/diamondback' cmd = copy.copy(self.rosinstall_fn) cmd.extend([self.directory, distrodir]) self.assertTrue(rosinstall_main(cmd)) self.assertEqual(0, subprocess.call(". %s" % os.path.join(self.directory, 'setup.sh'), shell=True, env=self.new_environ)) self.assertEqual(0, subprocess.call(". %s" % os.path.join(self.directory, 'setup.bash'), shell=True, env=self.new_environ, executable='/bin/bash')) p = subprocess.Popen("bash -c 'set -e; . %s'" % os.path.join(self.directory, 'setup.bash'), shell=True, stdout=subprocess.PIPE, env=self.new_environ) output = p.communicate() self.assertEqual(0, p.returncode) p = subprocess.Popen("bash -c '. %s; echo $ROS_ROOT'" % os.path.join(self.directory, 'setup.bash'), shell=True, stdout=subprocess.PIPE, env=self.new_environ) output = p.communicate() self.assertEqual('/opt/ros/diamondback/ros', output[0].decode('UTF-8').rstrip('\n')) p = subprocess.Popen("sh -c '. %s; echo $ROS_ROOT'" % os.path.join(self.directory, 'setup.sh'), shell=True, stdout=subprocess.PIPE, env=self.new_environ) output = p.communicate() self.assertEqual('/opt/ros/diamondback/ros', output[0].decode('UTF-8').rstrip('\n')) if os.path.isdir('/opt/ros/electric'): def test_local_electric(self): distrodir = '/opt/ros/electric' cmd = copy.copy(self.rosinstall_fn) cmd.extend([self.directory, distrodir]) self.assertTrue(rosinstall_main(cmd)) self.assertEqual(0, subprocess.call(". %s" % os.path.join(self.directory, 'setup.sh'), shell=True, env=self.new_environ)) self.assertEqual(0, subprocess.call(". %s" % os.path.join(self.directory, 'setup.bash'), shell=True, env=self.new_environ, executable='/bin/bash')) p = subprocess.Popen("bash -c 'set -e; . %s'" % os.path.join(self.directory, 'setup.bash'), shell=True, stdout=subprocess.PIPE, env=self.new_environ) output = p.communicate() self.assertEqual(0, p.returncode, (output, p.returncode)) p = subprocess.Popen("bash -c '. %s; echo $ROS_ROOT'" % os.path.join(self.directory, 'setup.bash'), shell=True, stdout=subprocess.PIPE, env=self.new_environ) output = p.communicate() self.assertEqual('/opt/ros/electric/ros', output[0].decode('UTF-8').rstrip('\n')) p = subprocess.Popen("sh -c '. %s; echo $ROS_ROOT'" % os.path.join(self.directory, 'setup.sh'), shell=True, stdout=subprocess.PIPE, env=self.new_environ) output = p.communicate() self.assertEqual('/opt/ros/electric/ros', output[0].decode('UTF-8').rstrip('\n')) if os.path.isdir('/opt/ros/fuerte'): def test_local_fuerte(self): distrodir = '/opt/ros/fuerte' cmd = copy.copy(self.rosinstall_fn) cmd.extend([self.directory, distrodir]) self.assertTrue(rosinstall_main(cmd)) self.assertEqual(0, subprocess.call(". %s" % os.path.join(self.directory, 'setup.sh'), shell=True, env=self.new_environ)) self.assertEqual(0, subprocess.call(". %s" % os.path.join(self.directory, 'setup.bash'), shell=True, env=self.new_environ, executable='/bin/bash')) p = subprocess.Popen("bash -c 'set -e; . %s'" % os.path.join(self.directory, 'setup.bash'), shell=True, stdout=subprocess.PIPE, env=self.new_environ) output = p.communicate() self.assertEqual(0, p.returncode, (output, p.returncode)) p = subprocess.Popen("bash -c '. %s; echo $ROS_ROOT'" % os.path.join(self.directory, 'setup.bash'), shell=True, stdout=subprocess.PIPE, env=self.new_environ) output = p.communicate() self.assertEqual('/opt/ros/fuerte/share/ros', output[0].decode('UTF-8').rstrip('\n')) p = subprocess.Popen("sh -c '. %s; echo $ROS_ROOT'" % os.path.join(self.directory, 'setup.sh'), shell=True, stdout=subprocess.PIPE, env=self.new_environ) output = p.communicate() self.assertEqual('/opt/ros/fuerte/share/ros', output[0].decode('UTF-8').rstrip('\n')) if os.path.isdir('/opt/ros/fuerte'): def test_local_fuerte_catkin(self): distrodir = '/opt/ros/fuerte' cmd = copy.copy(self.rosinstall_fn) cmd.extend([self.directory, distrodir, '--catkin']) self.assertTrue(rosinstall_main(cmd)) self.assertTrue(os.path.exists(os.path.join(self.directory, 'CMakeLists.txt'))) rosinstall-0.7.8/test/local/test_rosinstall_standalone_functions.py000066400000000000000000000132151272067315000261010ustar00rootroot00000000000000# Software License Agreement (BSD License) # # 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 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 unittest import subprocess import sys import rosinstall.helpers from wstool.config import Config from wstool.config_yaml import PathSpec from mock import Mock class FunctionsTest(unittest.TestCase): def setUp(self): pass def tearDown(self): pass def test_is_ros_in_setupfile(self): try: mock_subprocess = Mock() mock_process = Mock(name='mockprocess') mock_subprocess.Popen.return_value = mock_process if sys.version < '3': mock_process.communicate.return_value = ('/somewhere/mock_ros_root/foo/..', None) else: mock_process.communicate.return_value = (b'/somewhere/mock_ros_root/foo/..', None) mock_os = Mock() mock_path = Mock() mock_os.path = mock_path mock_os.environ = {} mock_path.split = os.path.split mock_path.normpath = os.path.normpath mock_path.isfile.return_value = True rosinstall.helpers.subprocess = mock_subprocess rosinstall.helpers.os = mock_os result = rosinstall.helpers.get_ros_root_from_setupfile("fooroot/foodir/setup.sh") self.assertEqual('/somewhere/mock_ros_root', os.path.normpath(result)) finally: rosinstall.helpers.subprocess = subprocess rosinstall.helpers.os = os def test_is_path_stack(self): self.assertTrue(rosinstall.helpers.is_path_stack(os.path.join("test", "example_dirs", "ros"))) self.assertTrue(rosinstall.helpers.is_path_stack(os.path.join("test", "example_dirs", "ros_comm"))) self.assertFalse(rosinstall.helpers.is_path_stack(os.path.join("test", "example_dirs", "roscpp"))) def test_is_path_ros(self): self.assertTrue(rosinstall.helpers.is_path_ros((os.path.join("test", "example_dirs", "ros")))) self.assertFalse(rosinstall.helpers.is_path_ros(os.path.join("test", "example_dirs", "ros_comm"))) self.assertFalse(rosinstall.helpers.is_path_ros((os.path.join("test", "example_dirs", "roscpp")))) def test_get_ros_stack_path(self): config = Config([PathSpec("foo"), PathSpec(os.path.join("test", "example_dirs", "ros_comm")), PathSpec(os.path.join("test", "example_dirs", "roscpp")), PathSpec("bar")], ".", None) self.assertEqual(None, rosinstall.helpers.get_ros_stack_path(config)) config = Config([PathSpec("foo"), PathSpec(os.path.join("test", "example_dirs", "ros_comm")), PathSpec(os.path.join("test", "example_dirs", "ros")), PathSpec(os.path.join("test", "example_dirs", "roscpp")), PathSpec("bar")], ".", None) self.assertEqual(os.path.abspath("test/example_dirs/ros"), rosinstall.helpers.get_ros_stack_path(config)) def test_get_ros_package_path(self): config = Config([], "/test/example_dirs", None) self.assertEqual([], rosinstall.helpers.get_ros_package_path(config)) config = Config([PathSpec("foo")], "/test/example_dirs", None) self.assertEqual(['/test/example_dirs/foo'], rosinstall.helpers.get_ros_package_path(config)) config = Config([PathSpec("foo"), PathSpec(os.path.join("test", "example_dirs", "ros_comm")), PathSpec(os.path.join("test", "example_dirs", "ros")), PathSpec(os.path.join("test", "example_dirs", "roscpp")), PathSpec("bar")], ".", None) self.assertEqual(list(map(os.path.abspath, ['bar', 'test/example_dirs/roscpp', 'test/example_dirs/ros_comm', 'foo'])), rosinstall.helpers.get_ros_package_path(config)) rosinstall-0.7.8/test/local/test_rosws.py000066400000000000000000000432361272067315000205720ustar00rootroot00000000000000# Software License Agreement (BSD License) # # 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 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 import subprocess import wstool import wstool.helpers from test.io_wrapper import StringIO import wstool.multiproject_cmd from test.scm_test_base import AbstractFakeRosBasedTest from rosinstall.rosws_cli import RoswsCLI class RosWsTest(AbstractFakeRosBasedTest): def setUp(self): """runs wstool with generated self.simple_rosinstall to create local wstool env and creates a directory for a second local wstool env""" AbstractFakeRosBasedTest.setUp(self) def test_init(self): workspace = os.path.join(self.test_root_path, 'ws1') cli = RoswsCLI() try: cli.cmd_init([workspace, 'foo', 'bar']) fail("expected exit") except SystemExit: pass self.assertEqual(0, cli.cmd_init([workspace, self.simple_rosinstall])) self.assertTrue(os.path.exists(workspace)) self.assertTrue(os.path.exists(os.path.join(workspace, '.rosinstall'))) self.assertTrue(os.path.exists(os.path.join(workspace, 'setup.sh'))) self.assertTrue(os.path.isdir(os.path.join(workspace, 'ros'))) self.assertTrue(os.path.isdir(os.path.join(workspace, 'gitrepo'))) self.assertTrue(os.path.isdir(os.path.join(workspace, 'gitrepo', '.git'))) config = wstool.multiproject_cmd.get_config(workspace, config_filename='.rosinstall') self.assertEqual(2, len(config.get_config_elements())) def test_init_pwd(self): workspace = os.path.join(self.test_root_path, 'ws1b') cli = RoswsCLI() self.assertEqual(0, cli.cmd_init([workspace])) self.assertTrue(os.path.exists(workspace)) self.assertTrue(os.path.exists(os.path.join(workspace, '.rosinstall'))) self.assertTrue(os.path.exists(os.path.join(workspace, 'setup.sh'))) config = wstool.multiproject_cmd.get_config(workspace, config_filename='.rosinstall') self.assertEqual(0, len(config.get_config_elements())) def test_init_parallel(self): workspace = os.path.join(self.test_root_path, 'ws1d') cli = RoswsCLI() self.assertEqual(0, cli.cmd_init([workspace, self.simple_rosinstall, "--parallel=5"])) self.assertTrue(os.path.exists(workspace)) self.assertTrue(os.path.exists(os.path.join(workspace, '.rosinstall'))) def test_merge(self): workspace = os.path.join(self.test_root_path, 'ws2') cli = RoswsCLI() self.assertEqual(0, cli.cmd_init([workspace, self.simple_rosinstall])) self.assertEqual(0, cli.cmd_merge(workspace, [self.simple_changed_vcs_rosinstall, '-y'])) self.assertFalse(os.path.isdir(os.path.join(workspace, 'hgrepo'))) self.assertFalse(os.path.isdir(os.path.join(workspace, 'hgrepo', '.hg'))) self.assertEqual(0, cli.cmd_update(workspace, [])) self.assertTrue(os.path.isdir(os.path.join(workspace, 'hgrepo'))) self.assertTrue(os.path.isdir(os.path.join(workspace, 'hgrepo', '.hg'))) config = wstool.multiproject_cmd.get_config(workspace, config_filename='.rosinstall') self.assertEqual(3, len(config.get_config_elements())) def test_remove(self): workspace = os.path.join(self.test_root_path, 'ws3') cli = RoswsCLI() self.assertEqual(0, cli.cmd_init([workspace, self.simple_rosinstall])) self.assertEqual(0, cli.cmd_merge(workspace, [self.simple_changed_vcs_rosinstall, '-y'])) self.assertEqual(0, cli.cmd_update(workspace, [])) config = wstool.multiproject_cmd.get_config(workspace, config_filename='.rosinstall') self.assertEqual(3, len(config.get_config_elements())) self.assertEqual(0, cli.cmd_remove(workspace, ['hgrepo'])) config = wstool.multiproject_cmd.get_config(workspace, config_filename='.rosinstall') self.assertEqual(2, len(config.get_config_elements())) def test_set_detached(self): workspace = os.path.join(self.test_root_path, 'ws4') cli = RoswsCLI() self.assertEqual(0, cli.cmd_init([workspace, self.simple_rosinstall])) self.assertEqual(0, cli.cmd_merge(workspace, [self.simple_changed_vcs_rosinstall, '-y'])) self.assertEqual(0, cli.cmd_update(workspace, [])) config = wstool.multiproject_cmd.get_config(workspace, config_filename='.rosinstall') self.assertEqual(3, len(config.get_config_elements())) self.assertEqual('ros', config.get_config_elements()[0].get_local_name()) self.assertEqual('gitrepo', config.get_config_elements()[1].get_local_name()) self.assertEqual(True, config.get_config_elements()[1].is_vcs_element()) self.assertEqual('hgrepo', config.get_config_elements()[2].get_local_name()) self.assertEqual(0, cli.cmd_set(workspace, [os.path.join(workspace, 'gitrepo'), '--detached', '-y'])) config = wstool.multiproject_cmd.get_config(workspace, config_filename='.rosinstall') self.assertEqual(3, len(config.get_config_elements())) self.assertEqual('ros', config.get_config_elements()[0].get_local_name()) self.assertEqual('gitrepo', config.get_config_elements()[1].get_local_name()) self.assertEqual(False, config.get_config_elements()[1].is_vcs_element()) self.assertEqual('hgrepo', config.get_config_elements()[2].get_local_name()) def test_set_add_plain(self): workspace = os.path.join(self.test_root_path, 'ws5') cli = RoswsCLI() self.assertEqual(0, cli.cmd_init([workspace, self.simple_rosinstall])) config = wstool.multiproject_cmd.get_config(workspace, config_filename='.rosinstall') self.assertEqual(2, len(config.get_config_elements())) self.assertEqual('ros', config.get_config_elements()[0].get_local_name()) self.assertEqual('gitrepo', config.get_config_elements()[1].get_local_name()) # detached self.assertEqual(0, cli.cmd_set(workspace, [os.path.join(workspace, 'foo'), '-y'])) config = wstool.multiproject_cmd.get_config(workspace, config_filename='.rosinstall') self.assertEqual(3, len(config.get_config_elements())) self.assertEqual('ros', config.get_config_elements()[0].get_local_name()) self.assertEqual('gitrepo', config.get_config_elements()[1].get_local_name()) self.assertEqual(False, config.get_config_elements()[2].is_vcs_element()) self.assertEqual('foo', config.get_config_elements()[2].get_local_name()) self.assertEqual(0, cli.cmd_set(workspace, [os.path.join(workspace, 'hgrepo'), '-y', '--detached'])) config = wstool.multiproject_cmd.get_config(workspace, config_filename='.rosinstall') self.assertEqual(4, len(config.get_config_elements())) self.assertEqual('ros', config.get_config_elements()[0].get_local_name()) self.assertEqual('gitrepo', config.get_config_elements()[1].get_local_name()) self.assertEqual(False, config.get_config_elements()[2].is_vcs_element()) self.assertEqual('foo', config.get_config_elements()[2].get_local_name()) self.assertEqual(False, config.get_config_elements()[3].is_vcs_element()) self.assertEqual('hgrepo', config.get_config_elements()[3].get_local_name()) # turn into scm repo self.assertEqual(0, cli.cmd_set(workspace, [os.path.join(workspace, 'hgrepo'), '../hgrepo', '-y', '--hg'])) config = wstool.multiproject_cmd.get_config(workspace, config_filename='.rosinstall') self.assertEqual(4, len(config.get_config_elements())) self.assertEqual('ros', config.get_config_elements()[0].get_local_name()) self.assertEqual('gitrepo', config.get_config_elements()[1].get_local_name()) self.assertTrue(config.get_config_elements()[3].is_vcs_element()) self.assertEqual('hgrepo', config.get_config_elements()[3].get_local_name()) def test_set_add_scm(self): workspace = os.path.join(self.test_root_path, 'ws6') cli = RoswsCLI() self.assertEqual(0, cli.cmd_init([workspace, self.simple_rosinstall])) config = wstool.multiproject_cmd.get_config(workspace, config_filename='.rosinstall') self.assertEqual(2, len(config.get_config_elements())) self.assertEqual('ros', config.get_config_elements()[0].get_local_name()) self.assertEqual('gitrepo', config.get_config_elements()[1].get_local_name()) # scm repo self.assertEqual(0, cli.cmd_set(workspace, [os.path.join(workspace, 'hgrepo'), '../hgrepo', '-y', '--hg'])) config = wstool.multiproject_cmd.get_config(workspace, config_filename='.rosinstall') self.assertEqual(3, len(config.get_config_elements())) self.assertEqual('ros', config.get_config_elements()[0].get_local_name()) self.assertEqual('gitrepo', config.get_config_elements()[1].get_local_name()) self.assertTrue(config.get_config_elements()[2].is_vcs_element()) self.assertEqual('hgrepo', config.get_config_elements()[2].get_local_name()) self.assertFalse(os.path.exists(os.path.join(workspace, 'hgrepo'))) self.assertEqual(0, cli.cmd_update(workspace, [])) self.assertTrue(os.path.exists(os.path.join(workspace, 'hgrepo'))) path_spec = config.get_config_elements()[2].get_versioned_path_spec() self.assertFalse(path_spec is None) self.assertEqual(None, path_spec.get_version()) self.assertEqual(None, path_spec.get_revision()) self.assertFalse(path_spec.get_current_revision() is None) self.assertEqual(0, cli.cmd_set(workspace, [os.path.join(workspace, 'hgrepo'), '--version-new=0', '-y'])) config = wstool.multiproject_cmd.get_config(workspace, config_filename='.rosinstall') path_spec = config.get_config_elements()[2].get_versioned_path_spec() self.assertEqual('0', path_spec.get_version()) self.assertFalse(path_spec.get_revision() is None) self.assertFalse(path_spec.get_current_revision() is None) self.assertEqual(path_spec.get_revision(), path_spec.get_current_revision()) # change in FS to version 1 subprocess.check_call(["touch", "hgfixed2.txt"], cwd=os.path.join(workspace, 'hgrepo')) subprocess.check_call(["hg", "add", "hgfixed2.txt"], cwd=os.path.join(workspace, 'hgrepo')) subprocess.check_call(["hg", "commit", "-m", "2nd"], cwd=os.path.join(workspace, 'hgrepo')) self.assertTrue(os.path.exists(os.path.join(workspace, 'hgrepo', 'hgfixed2.txt'))) path_spec = config.get_config_elements()[2].get_versioned_path_spec() self.assertEqual('0', path_spec.get_version()) self.assertFalse(path_spec.get_revision() is None) self.assertFalse(path_spec.get_current_revision() is None) self.assertNotEqual(path_spec.get_revision(), path_spec.get_current_revision()) # revert FS to spec self.assertEqual(0, cli.cmd_update(workspace, [])) config = wstool.multiproject_cmd.get_config(workspace, config_filename='.rosinstall') path_spec = config.get_config_elements()[2].get_versioned_path_spec() self.assertEqual('0', path_spec.get_version()) self.assertFalse(path_spec.get_revision() is None) self.assertFalse(path_spec.get_current_revision() is None) self.assertEqual(path_spec.get_revision(), path_spec.get_current_revision()) # change spec to 1 self.assertEqual(0, cli.cmd_set(workspace, [os.path.join(workspace, 'hgrepo'), '--version-new=1', '-y'])) config = wstool.multiproject_cmd.get_config(workspace, config_filename='.rosinstall') path_spec = config.get_config_elements()[2].get_versioned_path_spec() self.assertEqual('1', path_spec.get_version()) self.assertFalse(path_spec.get_revision() is None) self.assertFalse(path_spec.get_current_revision() is None) self.assertNotEqual(path_spec.get_revision(), path_spec.get_current_revision()) # setting version to '' self.assertEqual(0, cli.cmd_set(workspace, [os.path.join(workspace, 'hgrepo'), "--version-new=''", '-y'])) config = wstool.multiproject_cmd.get_config(workspace, config_filename='.rosinstall') path_spec = config.get_config_elements()[2].get_versioned_path_spec() self.assertEqual(None, path_spec.get_version()) self.assertTrue(path_spec.get_revision() is None) self.assertFalse(path_spec.get_current_revision() is None) self.assertEqual(0, cli.cmd_update(workspace, [])) config = wstool.multiproject_cmd.get_config(workspace, config_filename='.rosinstall') path_spec = config.get_config_elements()[2].get_versioned_path_spec() self.assertEqual(None, path_spec.get_version()) self.assertTrue(path_spec.get_revision() is None) self.assertFalse(path_spec.get_current_revision() is None) def test_info_only(self): workspace = os.path.join(self.test_root_path, 'ws7') cli = RoswsCLI() self.assertEqual(0, cli.cmd_init([workspace, self.simple_rosinstall])) # pkg_path sys.stdout = output = StringIO() self.assertEqual(0, cli.cmd_info(workspace, ['--pkg-path-only'])) output = output.getvalue() self.assertEqual(os.path.join(workspace, 'gitrepo'), output.strip()) sys.stdout = output = StringIO() self.assertEqual(0, cli.cmd_info(workspace, ['--only=localname'])) output = output.getvalue() self.assertEqual('ros\ngitrepo', output.strip()) sys.stdout = output = StringIO() self.assertEqual(0, cli.cmd_info(workspace, ['--only=version'])) output = output.getvalue() self.assertEqual('', output.strip()) sys.stdout = output = StringIO() self.assertEqual(0, cli.cmd_info(workspace, ['--only=uri'])) output = output.getvalue() self.assertEqual('%s\n%s\n' % (os.path.join(self.test_root_path, 'ros'), os.path.join(self.test_root_path, 'gitrepo')), output) sys.stdout = output = StringIO() self.assertEqual(0, cli.cmd_info(workspace, ['--only=cur_revision'])) output = output.getvalue() self.assertEqual(82, len(output)) sys.stdout = sys.__stdout__ # pairs sys.stdout = output = StringIO(); self.assertEqual(0, cli.cmd_info(workspace, ['--only=localname,scmtype'])) output = output.getvalue() self.assertEqual('ros,git\ngitrepo,git', output.strip()) sys.stdout = output = StringIO(); self.assertEqual(0, cli.cmd_info(workspace, ['--only=scmtype,localname'])) output = output.getvalue() self.assertEqual('git,ros\ngit,gitrepo', output.strip()) def test_set_add_scm_change_localname(self): workspace = os.path.join(self.test_root_path, 'ws8') cli = RoswsCLI() self.assertEqual(0, cli.cmd_init([workspace, self.ros_path])) config = wstool.multiproject_cmd.get_config(workspace, config_filename='.rosinstall') self.assertEqual(1, len(config.get_config_elements())) self.assertEqual(os.path.join(self.test_root_path, 'ros'), config.get_config_elements()[0].get_local_name()) # use a weird absolute localname self.assertEqual(0, cli.cmd_set(workspace, [os.path.join(workspace, '..', 'ws8', 'hgrepo'), '../hgrepo', '-y', '--hg'])) config = wstool.multiproject_cmd.get_config(workspace, config_filename='.rosinstall') self.assertEqual(2, len(config.get_config_elements())) self.assertEqual('hgrepo', config.get_config_elements()[1].get_local_name()) oldcwd = os.getcwd() try: os.chdir(self.test_root_path) # try pointing to a relative dir that also exists elsewhere try: cli.cmd_set(workspace, ['gitrepo', '../gitrepo', '-y', '--hg']) self.fail("Expected SystemExit") except SystemExit: pass # use a weird relative localname self.assertEqual(0, cli.cmd_set(workspace, [os.path.join('ws8', 'gitrepo'), '../gitrepo', '-y', '--hg'])) config = wstool.multiproject_cmd.get_config(workspace, config_filename='.rosinstall') self.assertEqual(3, len(config.get_config_elements())) self.assertEqual('hgrepo', config.get_config_elements()[1].get_local_name()) self.assertEqual('gitrepo', config.get_config_elements()[2].get_local_name()) finally: os.chdir(oldcwd) rosinstall-0.7.8/test/local/test_setupfiles.py000066400000000000000000000345211272067315000215750ustar00rootroot00000000000000# Software License Agreement (BSD License) # # 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 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 subprocess import rosinstall.setupfiles import wstool.helpers from wstool.config import Config from wstool.config_yaml import PathSpec, generate_config_yaml from rosinstall.helpers import ROSInstallException from wstool.helpers import ROSINSTALL_FILENAME from wstool.multiproject_cmd import cmd_persist_config from rosinstall.rosinstall_cmd import cmd_generate_ros_files from test.scm_test_base import AbstractFakeRosBasedTest from test.scm_test_base import AbstractRosinstallBaseDirTest def has_python3(): cmd = "python3 --version" p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) output, err = p.communicate() p.stdout.close() if not p.returncode == 0: return True return False HAS_PYTHON3 = has_python3() if 'ROSINSTALL_SKIP_PYTHON3' in os.environ: HAS_PYTHON3 = False def _add_to_file(path, content): """Util function to append to file to get a modification""" with open(path, 'ab') as f: f.write(content.encode('UTF-8')) class GenerateTest(AbstractFakeRosBasedTest): def test_gen_setup(self): try: config = Config([PathSpec(os.path.join("test", "example_dirs", "ros_comm")), PathSpec("bar")], self.test_root_path, None) rosinstall.setupfiles.generate_setup(config) self.fail('expected exception') except ROSInstallException: pass config = Config([PathSpec(self.ros_path), PathSpec(os.path.join("test", "example_dirs", "ros_comm")), PathSpec("bar")], self.test_root_path, None) rosinstall.setupfiles.generate_setup(config) self.assertTrue(os.path.isfile(os.path.join(self.test_root_path, 'setup.sh'))) self.assertTrue(os.path.isfile(os.path.join(self.test_root_path, 'setup.bash'))) self.assertTrue(os.path.isfile(os.path.join(self.test_root_path, 'setup.zsh'))) def test_gen_setupsh(self): config = Config([PathSpec(self.ros_path), PathSpec(os.path.join("test", "example_dirs", "ros_comm")), PathSpec("bar")], self.test_root_path, None) result = rosinstall.setupfiles.generate_setup_sh_text(config.get_base_path()) self.assertTrue(result.count("#!/usr/bin/env sh") == 1) config = Config([PathSpec(self.ros_path), PathSpec(os.path.join("test", "example_dirs", "ros_comm")), PathSpec("bar.sh", tags=['setup-file'])], self.test_root_path, None) result = rosinstall.setupfiles.generate_setup_sh_text(config.get_base_path()) self.assertTrue(result.count("#!/usr/bin/env sh") == 1, result) def test_source_setup_sh(self): test_folder = os.path.join(self.test_root_path, 'workspacetest') os.makedirs(test_folder) othersetupfile = os.path.join(test_folder, 'othersetup.sh') testsetupfile = os.path.join(test_folder, 'testsetup.sh') with open(othersetupfile, 'w') as fhand: fhand.write('unset ROS_WORKSPACE') config = Config([PathSpec(self.ros_path), PathSpec(othersetupfile, scmtype=None, tags=['setup-file'])], install_path=test_folder, config_filename=ROSINSTALL_FILENAME) result = rosinstall.setupfiles.generate_setup_sh_text(config.get_base_path()) self.assertTrue('export ROS_WORKSPACE=%s' % test_folder in result) with open(testsetupfile, 'w') as fhand: fhand.write(result) # check that sourcing setup.sh raises error when .wstool is missing raised = False try: subprocess.check_call(". %s" % testsetupfile , shell=True, env=self.new_environ) except: raised = True self.assertTrue(raised, 'sourcing setup.sh with missing .wstool should fail') # test that our otherscript really unsets ROS_WORKSPACE, else nexttest would be invalid # using basename to check var is not set raised = False try: cmd = "export ROS_WORKSPACE=foo && . %s && basename $ROS_WORKSPACE" % othersetupfile subprocess.check_call( cmd, shell=True, env=self.new_environ) except: raised = True self.assertTrue(raised, 'unsetting-sh-file did not unset var') # now test that when sourcing setup.sh that contains a # setup-file to other sh file which unsets ROS_WORKSPACE, # ROS_WORKSPACE is still set in the end generate_config_yaml(config, ROSINSTALL_FILENAME, '') self.assertTrue(os.path.isfile(os.path.join(test_folder, ROSINSTALL_FILENAME))) # using basename to check var is set cmd = "export ROS_WORKSPACE=foo && . %s && echo $ROS_WORKSPACE" % testsetupfile po = subprocess.Popen(cmd, shell=True, cwd=test_folder, stdout=subprocess.PIPE) workspace = po.stdout.read().decode('UTF-8').rstrip('"').lstrip('"').strip() po.stdout.close() self.assertEqual(test_folder, workspace) def test_source_setup_sh_chain(self): """ Tests chaining of workspaces, which is fragile because sourcing very similar setup.sh files recursively """ chain_root_path = os.path.join(self.test_root_path, 'chaintest') os.makedirs(chain_root_path) test_folder1 = os.path.join(chain_root_path, 'ws1') os.makedirs(test_folder1) test_folder2 = os.path.join(chain_root_path, 'ws2') os.makedirs(test_folder2) test_folder3 = os.path.join(chain_root_path, 'ws3') os.makedirs(test_folder3) test_folder4 = os.path.join(chain_root_path, 'ws4') os.makedirs(test_folder4) othersetupfile = os.path.join(chain_root_path, 'othersetup.sh') with open(othersetupfile, 'w') as fhand: fhand.write('export ROS_PACKAGE_PATH=/opt/ros/distro') config1 = Config([PathSpec('ws1sub'), PathSpec(os.path.join(test_folder2, "setup.sh"), scmtype=None, tags=['setup-file']), PathSpec(os.path.join(test_folder4, "setup.sh"), scmtype=None, tags=['setup-file'])], install_path=test_folder1, config_filename=ROSINSTALL_FILENAME) config2 = Config([PathSpec('ws2sub'), PathSpec(os.path.join(test_folder3, "setup.sh"), scmtype=None, tags=['setup-file'])], install_path=test_folder2, config_filename=ROSINSTALL_FILENAME) config3 = Config([PathSpec('ws3sub'), PathSpec(othersetupfile, scmtype=None, tags=['setup-file'])], install_path=test_folder3, config_filename=ROSINSTALL_FILENAME) config4 = Config([PathSpec('ws4sub')], install_path=test_folder4, config_filename=ROSINSTALL_FILENAME) cmd_generate_ros_files(config1, test_folder1, no_ros_allowed=True) cmd_persist_config(config1, os.path.join(test_folder1, ROSINSTALL_FILENAME)) cmd_generate_ros_files(config2, test_folder2, no_ros_allowed=True) cmd_persist_config(config2, os.path.join(test_folder2, ROSINSTALL_FILENAME)) cmd_generate_ros_files(config3, test_folder3, no_ros_allowed=True) cmd_persist_config(config3, os.path.join(test_folder3, ROSINSTALL_FILENAME)) cmd_generate_ros_files(config4, test_folder4, no_ros_allowed=True) cmd_persist_config(config4, os.path.join(test_folder4, ROSINSTALL_FILENAME)) cmd = ". %s && echo $ROS_PACKAGE_PATH" % os.path.join(test_folder1, "setup.sh") po = subprocess.Popen(cmd, shell=True, cwd=test_folder1, stdout=subprocess.PIPE) ppath = po.stdout.read().decode('UTF-8').strip('"').strip() po.stdout.close() expected = ':'.join([os.path.join(test_folder1, "ws1sub"), os.path.join(test_folder2, "ws2sub"), os.path.join(test_folder3, "ws3sub"), os.path.join(test_folder4, "ws4sub"), '/opt/ros/distro']) self.assertEqual(expected, ppath) # test double sourcing cmd = ". %s ; . %s && echo $ROS_PACKAGE_PATH" % (os.path.join(test_folder2, "setup.sh"), os.path.join(test_folder4, "setup.sh")) po = subprocess.Popen(cmd, shell=True, cwd=test_folder1, stdout=subprocess.PIPE) ppath = po.stdout.read().decode('UTF-8').strip('"').strip() po.stdout.close() expected = os.path.join(test_folder4, "ws4sub") self.assertEqual(expected, ppath) def test_gen_setup_bash(self): config = Config([PathSpec(self.ros_path), PathSpec(os.path.join("test", "example_dirs", "ros_comm")), PathSpec("bar")], self.test_root_path, None) result = rosinstall.setupfiles.generate_setup_bash_text('bash') self.assertTrue(result.count("#!/usr/bin/env bash") == 1) self.assertTrue(result.count("CATKIN_SHELL=bash") == 1) self.assertTrue(result.count("ROSSHELL_PATH=`rospack find rosbash`/rosbash") == 1) result = rosinstall.setupfiles.generate_setup_bash_text('zsh') self.assertTrue(result.count("#!/usr/bin/env zsh") == 1) self.assertTrue(result.count("CATKIN_SHELL=zsh") == 1) self.assertTrue(result.count("ROSSHELL_PATH=`rospack find rosbash`/roszsh") == 1) class Genfiletest(AbstractRosinstallBaseDirTest): def test_gen_python_code(self): config = Config( [PathSpec(os.path.join("test", "example_dirs", "ros_comm")), PathSpec("bar.sh", tags=['setup-file']), PathSpec("baz")], self.directory, None) wstool.config_yaml.generate_config_yaml(config, '.rosinstall', '') filename = os.path.join(self.directory, "test_gen.py") _add_to_file(filename, rosinstall.setupfiles.generate_embedded_python()) sh_filename = os.path.join(self.directory, "bar.sh") _add_to_file(sh_filename, "#! /usr/bin/env sh") cmd = "python -W ignore %s" % filename p = subprocess.Popen(cmd, shell=True, cwd=self.directory, stdout=subprocess.PIPE, stderr=subprocess.PIPE) output, err = p.communicate() self.assertEqual(''.encode('UTF-8'), err, err) self.assertTrue('/test/example_dirs/ros_comm'.encode('UTF-8') in output, output) self.assertTrue('baz'.encode('UTF-8') in output, output) self.assertTrue('ROSINSTALL_PATH_SETUPFILE_SEPARATOR'.encode('UTF-8') in output, output) self.assertTrue(output.endswith('/bar.sh\n'.encode('UTF-8')), output) if HAS_PYTHON3: def test_gen_python_code_python3(self): # requires python3 to be installed, obviously config = Config([PathSpec(os.path.join("test", "example_dirs", "ros_comm")), PathSpec("bar.sh", tags=['setup-file']), PathSpec("baz")], self.directory, None) wstool.config_yaml.generate_config_yaml(config, '.rosinstall', '') filename = os.path.join(self.directory, "test_gen.py") _add_to_file(filename, rosinstall.setupfiles.generate_embedded_python()) sh_filename = os.path.join(self.directory, "bar.sh") _add_to_file(sh_filename, "#! /usr/bin/env sh") cmd = "python3 -W ignore %s" % filename p = subprocess.Popen(cmd, shell=True, cwd=self.directory, stdout=subprocess.PIPE, stderr=subprocess.PIPE) output, err = p.communicate() self.assertEqual(''.encode('UTF-8'), err, err) self.assertTrue('/test/example_dirs/ros_comm'.encode('UTF-8') in output, output) self.assertTrue('baz'.encode('UTF-8') in output, output) self.assertTrue('ROSINSTALL_PATH_SETUPFILE_SEPARATOR'.encode('UTF-8') in output, output) self.assertTrue(output.endswith('/bar.sh\n'.encode('UTF-8')), output) def main(): import unittest unittest.main() rosinstall-0.7.8/test/rosws_stacks/000077500000000000000000000000001272067315000174275ustar00rootroot00000000000000rosinstall-0.7.8/test/rosws_stacks/test_rosws_stacks.py000066400000000000000000000052211272067315000235650ustar00rootroot00000000000000import os import io import unittest import tempfile import shutil import rosinstall.helpers import rosinstall.rosws_stacks_cli from rosinstall.helpers import ROSInstallException from wstool.config import Config from wstool.config_yaml import PathSpec class RosWsStacksTest(unittest.TestCase): def test_get_distro(self): self.assertEqual('diamondback', rosinstall.rosws_stacks_cli.rosversion_to_distro_name([1, 4, 0])) self.assertEqual('electric', rosinstall.rosws_stacks_cli.rosversion_to_distro_name([1, 6, 0])) self.assertEqual('fuerte', rosinstall.rosws_stacks_cli.rosversion_to_distro_name([1, 8, 0])) self.assertEqual('groovy', rosinstall.rosws_stacks_cli.rosversion_to_distro_name([1, 10, 0])) try: self.assertEqual('groovy', rosinstall.rosws_stacks_cli.rosversion_to_distro_name([1])) self.fail('expected exception') except ROSInstallException: pass try: self.assertEqual('groovy', rosinstall.rosws_stacks_cli.rosversion_to_distro_name(['a', 'b'])) self.fail('expected exception') except ROSInstallException: pass def test_get_stack_element_in_config(self): self.test_root_path = tempfile.mkdtemp() self.install_path = os.path.join(self.test_root_path, "install") os.makedirs(self.install_path) f = io.open(os.path.join(self.install_path, 'stack.xml'), 'a') f.write(unicode("hello stack")) f.close() config = Config([PathSpec("foo"), PathSpec("install"), PathSpec("bar")], self.test_root_path, None) self.assertEqual(None, rosinstall.rosws_stacks_cli.get_stack_element_in_config(config, 'foo')) self.assertEqual(None, rosinstall.rosws_stacks_cli.get_stack_element_in_config(config, None)) el = rosinstall.rosws_stacks_cli.get_stack_element_in_config(config, 'install') self.assertEqual(self.install_path, el.get_path()) shutil.rmtree(self.test_root_path) def test_roslocate_info(self): yaml = rosinstall.rosws_stacks_cli.roslocate_info("ros_comm", "electric", False) self.assertEqual([{'svn': {'local-name': 'ros_comm', 'uri': 'https://code.ros.org/svn/ros/stacks/ros_comm/tags/ros_comm-1.6.6'}}], yaml) def xtest_get_ros_stack_version(self): ver = rosinstall.rosws_stacks_cli.get_ros_stack_version() assertTrue(ver[0] > 1) assertTrue(ver[1] >= 0) def test_get_dependent_stacks(self): dep_ons = rosinstall.rosws_stacks_cli.get_dependent_stacks('ros') self.assertTrue(len(dep_ons) > 1) rosinstall-0.7.8/test/scm_test_base.py000066400000000000000000000257031272067315000200760ustar00rootroot00000000000000# Software License Agreement (BSD License) # # 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 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 unicode_literals import os import copy import unittest import subprocess import tempfile import shutil def _add_to_file(path, content): """Util function to append to file to get a modification""" with open(path, 'ab') as fhand: fhand.write(content.encode('UTF-8')) def _create_fake_ros_dir(root_path): """setup fake ros root within root_path/ros""" ros_path = os.path.join(root_path, "ros") os.makedirs(ros_path) bin_path = os.path.join(ros_path, "bin") os.makedirs(bin_path) subprocess.check_call(["git", "init"], cwd=ros_path) _add_to_file(os.path.join(ros_path, "stack.xml"), '') _add_to_file(os.path.join(ros_path, "setup.sh"), 'export FOO_BAR=`pwd`') _add_to_file(os.path.join(bin_path, "rosmake"), '#!/usr/bin/env sh') _add_to_file(os.path.join(bin_path, "rospack"), '#!/usr/bin/env sh') # even faking rosmake subprocess.check_call(["chmod", "u+x", os.path.join(bin_path, "rosmake")]) subprocess.check_call(["chmod", "u+x", os.path.join(bin_path, "rospack")]) subprocess.check_call(["git", "add", "*"], cwd=ros_path) subprocess.check_call(["git", "commit", "-m", "initial"], cwd=ros_path) def _create_yaml_file(config_elements, path): content = '' for elt in list(config_elements): content += "- %s:\n" % elt["type"] if elt["uri"] is not None: content += " uri: '%s'\n" % elt["uri"] content += " local-name: '%s'\n" % elt["local-name"] if elt["version"] is not None: content += " version: '%s'\n" % elt["version"] _add_to_file(path, content) def _create_config_elt_dict(scmtype, localname, uri=None, version=None): element = {} element["type"] = scmtype element["uri"] = uri element["local-name"] = localname element["version"] = version return element def _create_git_repo(git_path): os.makedirs(git_path) subprocess.check_call(["git", "init"], cwd=git_path) subprocess.check_call(["touch", "gitfixed.txt"], cwd=git_path) subprocess.check_call(["git", "add", "*"], cwd=git_path) subprocess.check_call(["git", "commit", "-m", "initial"], cwd=git_path) def _create_tar_file(tar_file): parent_path = os.path.dirname(tar_file) tar_path = os.path.join(parent_path, 'temptar') os.makedirs(tar_path) subprocess.check_call(["touch", "tarfixed.txt"], cwd=tar_path) subprocess.check_call(["tar", "-czf", os.path.basename(tar_file), 'temptar'], cwd=parent_path) def _create_hg_repo(hg_path): os.makedirs(hg_path) subprocess.check_call(["hg", "init"], cwd=hg_path) subprocess.check_call(["touch", "hgfixed.txt"], cwd=hg_path) subprocess.check_call(["hg", "add", "hgfixed.txt"], cwd=hg_path) subprocess.check_call(["hg", "commit", "-m", "initial"], cwd=hg_path) def _nth_line_split(n, output): """returns the last line as list of non-blank tokens""" lines = output.splitlines() if len(lines) > 0: return lines[n].split() else: return [] # ROSINSTALL_CMD = os.path.join(os.getcwd(), 'scripts/rosinstall') # ROSWS_CMD = os.path.join(os.getcwd(), 'scripts/rosws') class AbstractRosinstallCLITest(unittest.TestCase): """Base class for cli tests""" @classmethod def setUpClass(self): self.new_environ = copy.copy(os.environ) self.new_environ["PYTHONPATH"] = os.path.join(os.getcwd(), "src") if "ROS_WORKSPACE" in self.new_environ: self.new_environ.pop("ROS_WORKSPACE") class AbstractRosinstallBaseDirTest(AbstractRosinstallCLITest): """test class where each test method get its own fresh tempdir named self.directory""" def setUp(self): self.directories = {} self.directory = tempfile.mkdtemp() self.directories["base"] = self.directory self.rosinstall_fn = ["rosinstall", "-n"] def tearDown(self): for d in self.directories: shutil.rmtree(self.directories[d]) self.directories = {} class AbstractFakeRosBasedTest(AbstractRosinstallBaseDirTest): """ creates some larger infrastructure for testing locally: a root folder containing all other folders in self.test_root_path a fake ros folder in self.ros_path a git repo in self.git_path a hg repo in self.hg_path a file named self.simple_rosinstall with ros and gitrepo a file named self.simple_changed_vcs_rosinstall with ros and hgrepo """ @classmethod def setUpClass(self): AbstractRosinstallBaseDirTest.setUpClass() # create a dir mimicking ros self.test_root_path = tempfile.mkdtemp() _create_fake_ros_dir(self.test_root_path) # create a repo in git self.ros_path = os.path.join(self.test_root_path, "ros") self.git_path = os.path.join(self.test_root_path, "gitrepo") _create_git_repo(self.git_path) # create a repo in hg self.hg_path = os.path.join(self.test_root_path, "hgrepo") _create_hg_repo(self.hg_path) # create custom rosinstall files to use as input self.simple_rosinstall = os.path.join(self.test_root_path, "simple.rosinstall") _create_yaml_file([_create_config_elt_dict("git", "ros", self.ros_path), _create_config_elt_dict("git", "gitrepo", self.git_path)], self.simple_rosinstall) self.simple_changed_vcs_rosinstall = os.path.join(self.test_root_path, "simple_changed_vcs.rosinstall") _create_yaml_file([_create_config_elt_dict("git", "ros", self.ros_path), _create_config_elt_dict("hg", "hgrepo", self.hg_path)], self.simple_changed_vcs_rosinstall) @classmethod def tearDownClass(self): shutil.rmtree(self.test_root_path) class AbstractSCMTest(AbstractRosinstallCLITest): """Base class for diff tests, setting up a tempdir self.test_root_path for a whole class""" @classmethod def setUpClass(self): """creates a directory 'ros' mimicking to be a ROS root to rosinstall""" AbstractRosinstallCLITest.setUpClass() self.test_root_path = tempfile.mkdtemp() self.directories = {} self.directories["root"] = self.test_root_path _create_fake_ros_dir(self.test_root_path) self.local_path = os.path.join(self.test_root_path, "ws") os.makedirs(self.local_path) self.curdir = os.getcwd() @classmethod def tearDownClass(self): os.chdir(self.curdir) for d in self.directories: shutil.rmtree(self.directories[d]) def assertStatusListEqual(self, listexpect, listactual): """helper fun to check scm status output while discarding file ordering differences""" lines_expect = listexpect.splitlines() lines_actual = listactual.splitlines() for line in lines_expect: self.assertTrue(line in lines_actual, 'Missing entry %s in output %s' % (line, listactual)) for line in lines_actual: self.assertTrue(line in lines_expect, 'Superflous entry %s in output %s' % (line, listactual)) class UtilTest(unittest.TestCase): """test to check the methods run by unit test setups""" def test_add_to_file(self): self.test_root_path = tempfile.mkdtemp() filepath = os.path.join(self.test_root_path, 'foofile') self.assertFalse(os.path.exists(filepath)) _add_to_file(filepath, 'foo') self.assertTrue(os.path.exists(filepath)) with open(filepath, 'r') as f: read_data = f.read() self.assertEqual(read_data, 'foo') _add_to_file(filepath, 'bar') with open(filepath, 'r') as f: read_data = f.read() self.assertEqual(read_data, 'foobar') shutil.rmtree(self.test_root_path) def test_create_fake_ros(self): self.test_root_path = tempfile.mkdtemp() rospath = os.path.join(self.test_root_path, 'ros') self.assertFalse(os.path.exists(rospath)) _create_fake_ros_dir(self.test_root_path) self.assertTrue(os.path.exists(rospath)) self.assertTrue(os.path.exists(os.path.join(rospath, "setup.sh"))) self.assertTrue(os.path.exists(os.path.join(rospath, "stack.xml"))) self.assertTrue(os.path.exists(os.path.join(rospath, ".git"))) shutil.rmtree(self.test_root_path) def test_create_config_elt_dict(self): scmtype = 'foo' uri = 'bar' localname = 'pip' version = 'pop' element = _create_config_elt_dict(scmtype, localname, uri, version) self.assertEqual(element["type"], scmtype) self.assertEqual(element["uri"], uri) self.assertEqual(element["local-name"], localname) self.assertEqual(element["version"], version) def test_create_yaml_file(self): self.test_root_path = tempfile.mkdtemp() filepath = os.path.join(self.test_root_path, 'foofile') config_elements = [ _create_config_elt_dict("other", "foo"), _create_config_elt_dict("git", "foo", "foouri"), _create_config_elt_dict("svn", "bar", "baruri", "barversion")] _create_yaml_file(config_elements, filepath) with open(filepath, 'r') as f: read_data = f.read() self.assertEqual(read_data, """- other: local-name: 'foo' - git: uri: 'foouri' local-name: 'foo' - svn: uri: 'baruri' local-name: 'bar' version: 'barversion' """) shutil.rmtree(self.test_root_path)