├── .gitignore
├── .travis.yml
├── CONTRIBUTING.rst
├── LICENSE
├── MANIFEST.in
├── Makefile
├── README.rst
├── completion
├── _wstool
└── wstool-completion.bash
├── doc
├── Makefile
├── changelog.rst
├── conf.py
├── developers_guide.rst
├── index.rst
├── make.bat
├── rosinstall_file_format.rst
└── wstool_usage.rst
├── requirements-test.txt
├── requirements.txt
├── scripts
└── wstool
├── setup.cfg
├── setup.py
├── src
└── wstool
│ ├── __init__.py
│ ├── __version__.py
│ ├── cli_common.py
│ ├── common.py
│ ├── config.py
│ ├── config_elements.py
│ ├── config_yaml.py
│ ├── helpers.py
│ ├── multiproject_cli.py
│ ├── multiproject_cmd.py
│ ├── ui.py
│ └── wstool_cli.py
├── stdeb.cfg
├── test
├── __init__.py
├── example.yaml
├── example_dirs
│ ├── ros
│ │ └── stack.xml
│ ├── ros_comm
│ │ └── stack.xml
│ └── roscpp
│ │ └── manifest.xml
├── io_wrapper.py
├── local
│ ├── __init__.py
│ ├── mock_client.py
│ ├── test_cli.py
│ ├── test_config.py
│ ├── test_config_elt.py
│ ├── test_config_yaml.py
│ ├── test_diff_functions_bzr.py
│ ├── test_diff_functions_git.py
│ ├── test_diff_functions_hg.py
│ ├── test_diff_functions_multi.py
│ ├── test_diff_functions_svn.py
│ ├── test_export.py
│ ├── test_interation.py
│ ├── test_multiproject_functions.py
│ ├── test_rosinstall_options.py
│ ├── test_rosinstall_standalone_functions.py
│ ├── test_shallow_checkout_git.py
│ └── test_tarfile.py
└── scm_test_base.py
└── tox.ini
/.gitignore:
--------------------------------------------------------------------------------
1 | *#
2 | *.DS_Store
3 | *.coverage
4 | *.deb
5 | *.egg-info
6 | *.eggs
7 | *.log
8 | *.orig
9 | *.pyc
10 | *.swp
11 | *.tgz
12 | *~
13 | .tox
14 | build/*
15 | description-pak
16 | dist
17 | doc-pak
18 | nosetests.xml
19 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: python
2 | python:
3 | - "2.7"
4 | - "3.5"
5 | - "3.6"
6 |
7 | # Add test requirements; travis will do the rest
8 | before_install:
9 | - cat requirements-test.txt >> requirements.txt
10 |
11 | install:
12 | - sudo apt-get update
13 | - pip install -U setuptools tox tox-travis
14 | - echo $PYTHONPATH
15 | - python -c 'import sys; print(sys.path)'
16 | - python setup.py install
17 | - python -c 'import coverage'
18 |
19 | # command to run tests
20 | script:
21 | - tox
22 |
23 | # Install rosinstall from pip and perform a sanity check
24 | - pip install --upgrade rosinstall wstool
25 | - rosws
26 | - wstool --help
27 |
28 | notifications:
29 | email: false
30 | after_success:
31 | - coveralls
32 |
--------------------------------------------------------------------------------
/CONTRIBUTING.rst:
--------------------------------------------------------------------------------
1 | Contributing guide
2 | ==================
3 |
4 | Thanks for your interest in contributing to wstool.
5 |
6 | Any kinds of contributions are welcome: Bug reports, Documentation, Patches.
7 |
8 | The core functionality of abstracting over different version control systems is contained in the library project https://github.com/vcstools/vcstools.
9 |
10 | Developer Environment
11 | ---------------------
12 |
13 | For many tasks, it is okay to just develop using a single installed python version. But if you need to test/debug the project in multiple python versions, you need to install those versions::
14 |
15 | 1. (Optional) Install multiple python versions
16 |
17 | 1. (Optional) Install [pyenv](https://github.com/pyenv/pyenv-installer) to manage python versions
18 | 2. (Optional) Using pyenv, install the python versions used in testing::
19 |
20 | pyenv install 2.7.16
21 | pyenv install 3.6.8
22 |
23 | It may be okay to run and test python against locally installed libraries, but if you need to have a consistent build, it is recommended to manage your environment using `virtualenv `_::
24 |
25 | $ virtualenv ~/wstool_venv
26 | $ source ~/wstool_venv/bin/activate
27 |
28 | Testing
29 | -------
30 |
31 | Prerequisites:
32 |
33 | * The tests require git, mercurial, bazaar and subversion to be installed.
34 |
35 | Also you need to install python test support libraries::
36 |
37 | # install python dependencies
38 | $ pip install .[test]
39 | # optional also use local vcstools sources directly
40 | $ pip install --editable /path/to/vcstools_source
41 |
42 | Then you can use different commands to run various test scopes::
43 |
44 | # run all tests using nose
45 | $ nosetests
46 | # run one test using nose
47 | $ nosetests {testname}
48 | # run all tests with coverage check
49 | $ python setup.py test
50 | # run all tests using python3
51 | $ python3 setup.py test
52 | # run all tests against multiple python versions (same as in travis)
53 | $ tox
54 |
55 | Releasing
56 | ---------
57 |
58 | * Upgrade vcstools dependency version in `requirements.txt`
59 | * Update `src/vcstools/__version__.py`
60 | * Check `doc/changelog` is up to date
61 | * Check `stdeb.cfg` is up to date with OSRF buildfarm distros
62 | * prepare release dependencies::
63 |
64 | pip install --upgrade setuptools wheel twine
65 |
66 | * Upload to testpypi::
67 |
68 | python3 setup.py sdist bdist_wheel
69 | twine upload --repository testpypi dist/*
70 | # in fresh virtualenv
71 | pip install -i https://test.pypi.org/simple/ wstool
72 |
73 | * Check testpypi download files and documentation look ok
74 | * Actually release::
75 |
76 | twine upload dist/*
77 |
78 | * Create and push tag::
79 |
80 | git tag x.y.z
81 | git push
82 | git push --tags
83 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | # Software License Agreement (BSD License)
2 | #
3 | # Copyright (c) 2010, Willow Garage, Inc.
4 | # All rights reserved.
5 | #
6 | # Redistribution and use in source and binary forms, with or without
7 | # modification, are permitted provided that the following conditions
8 | # are met:
9 | #
10 | # * Redistributions of source code must retain the above copyright
11 | # notice, this list of conditions and the following disclaimer.
12 | # * Redistributions in binary form must reproduce the above
13 | # copyright notice, this list of conditions and the following
14 | # disclaimer in the documentation and/or other materials provided
15 | # with the distribution.
16 | # * Neither the name of Willow Garage, Inc. nor the names of its
17 | # contributors may be used to endorse or promote products derived
18 | # from this software without specific prior written permission.
19 | #
20 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 | # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 | # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 | # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 | # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 | # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 | # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 | # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 | # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 | # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 | # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 | # POSSIBILITY OF SUCH DAMAGE.
32 |
33 |
--------------------------------------------------------------------------------
/MANIFEST.in:
--------------------------------------------------------------------------------
1 | include *.py
2 | include LICENSE
3 | recursive-include completion *
4 | recursive-include doc *
5 | include requirements.txt
6 | include requirements-test.txt
7 |
8 | global-exclude .tox
9 | global-exclude *~
10 | global-exclude __pycache__
11 | global-exclude .coverage
12 | global-exclude *.py[co]
13 | global-exclude *.db
14 | global-exclude .git*
15 | global-exclude *.orig
16 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | .PHONY: all setup clean_dist distro clean install testsetup test
2 |
3 | NAME='wstool'
4 | VERSION=$(shell grep version ./src/wstool/__version__.py | sed 's,version = ,,')
5 |
6 | OUTPUT_DIR=deb_dist
7 |
8 |
9 | all:
10 | echo "noop for debbuild"
11 |
12 | setup:
13 | echo "building version ${VERSION}"
14 |
15 | clean_dist:
16 | -rm -rf src/wstool.egg-info
17 | -rm -rf dist
18 | -rm -rf deb_dist
19 |
20 | distro: setup clean_dist
21 | python setup.py sdist
22 |
23 | clean: clean_dist
24 |
25 |
26 | install: distro
27 | sudo checkinstall python setup.py install
28 |
29 | testsetup:
30 | echo "running tests"
31 |
32 | test: testsetup
33 | nosetests --with-coverage --cover-package=wstool
34 |
--------------------------------------------------------------------------------
/README.rst:
--------------------------------------------------------------------------------
1 | Archived
2 | ========
3 | This repository has been archived due to a lack of maintainance and no longer being used in the ROS project.
4 | For similar functionality see http://wiki.ros.org/vcstool.
5 |
6 | wstool
7 | ==========
8 |
9 | .. image:: https://travis-ci.org/vcstools/wstool.svg?branch=master
10 | :target: https://travis-ci.org/vcstools/wstool
11 |
12 | .. image:: https://coveralls.io/repos/github/wstool/wstool/badge.svg?branch=master
13 | :target: https://coveralls.io/github/wstool/wstool?branch=master
14 |
15 | .. image:: https://img.shields.io/pypi/v/wstool.svg
16 | :target: https://pypi.python.org/pypi/wstool
17 |
18 | .. image:: https://img.shields.io/pypi/pyversions/wstool.svg
19 | :target: https://pypi.python.org/pypi/wstool
20 |
21 | .. image:: https://img.shields.io/pypi/status/wstool.svg
22 | :target: https://pypi.python.org/pypi/wstool
23 |
24 | .. image:: https://img.shields.io/pypi/l/wstool.svg
25 | :target: https://pypi.python.org/pypi/wstool
26 |
27 | .. image:: https://img.shields.io/pypi/dd/wstool.svg
28 | :target: https://pypi.python.org/pypi/wstool
29 |
30 | .. image:: https://img.shields.io/pypi/dw/wstool.svg
31 | :target: https://pypi.python.org/pypi/wstool
32 |
33 | .. image:: https://img.shields.io/pypi/dm/wstool.svg
34 | :target: https://pypi.python.org/pypi/wstool
35 |
36 | Command-line tools for maintaining a workspace of projects from multiple version-control systems.
37 |
38 | Also see http://wiki.ros.org/wstool.
39 |
40 | Installing
41 | ----------
42 |
43 | Using the pypi package::
44 |
45 | $ pip install -U wstool
46 |
--------------------------------------------------------------------------------
/completion/_wstool:
--------------------------------------------------------------------------------
1 | #compdef wstool
2 | # Software License Agreement (BSD License)
3 | #
4 | # Copyright (c) 2010, Willow Garage, Inc.
5 | # All rights reserved.
6 | #
7 | # Redistribution and use in source and binary forms, with or without
8 | # modification, are permitted provided that the following conditions
9 | # are met:
10 | #
11 | # * Redistributions of source code must retain the above copyright
12 | # notice, this list of conditions and the following disclaimer.
13 | # * Redistributions in binary form must reproduce the above
14 | # copyright notice, this list of conditions and the following
15 | # disclaimer in the documentation and/or other materials provided
16 | # with the distribution.
17 | # * Neither the name of Willow Garage, Inc. nor the names of its
18 | # contributors may be used to endorse or promote products derived
19 | # from this software without specific prior written permission.
20 | #
21 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 | # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 | # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24 | # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25 | # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26 | # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 | # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 | # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29 | # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 | # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31 | # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32 | # POSSIBILITY OF SUCH DAMAGE.
33 |
34 | _wstool () {
35 | local e
36 | e=$(dirname ${funcsourcetrace[1]%:*})/wstool-completion.bash
37 | if [ -f $e ]; then
38 | . $e
39 | fi
40 | }
41 |
--------------------------------------------------------------------------------
/completion/wstool-completion.bash:
--------------------------------------------------------------------------------
1 | # Software License Agreement (BSD License)
2 | #
3 | # Copyright (c) 2010, Willow Garage, Inc.
4 | # All rights reserved.
5 | #
6 | # Redistribution and use in source and binary forms, with or without
7 | # modification, are permitted provided that the following conditions
8 | # are met:
9 | #
10 | # * Redistributions of source code must retain the above copyright
11 | # notice, this list of conditions and the following disclaimer.
12 | # * Redistributions in binary form must reproduce the above
13 | # copyright notice, this list of conditions and the following
14 | # disclaimer in the documentation and/or other materials provided
15 | # with the distribution.
16 | # * Neither the name of Willow Garage, Inc. nor the names of its
17 | # contributors may be used to endorse or promote products derived
18 | # from this software without specific prior written permission.
19 | #
20 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 | # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 | # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 | # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 | # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 | # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 | # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 | # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 | # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 | # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 | # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 | # POSSIBILITY OF SUCH DAMAGE.
32 |
33 | # Programmable completion for the wstool command under bash. Source
34 | # this file (or on some systems add it to ~/.bash_completion and start a new
35 | # shell)
36 |
37 | # ZSH support
38 | if [[ -n ${ZSH_VERSION-} ]]; then
39 | autoload -U +X bashcompinit && bashcompinit
40 | fi
41 |
42 | # put here to be extendable
43 | if [ -z "$WSTOOL_BASE_COMMANDS" ]; then
44 | _WSTOOL_BASE_COMMANDS="help init set merge info remove diff status update export --version"
45 | fi
46 |
47 | # Based originally on the bzr/svn bash completition scripts.
48 | _wstool_complete()
49 | {
50 | local cur cmds cmdOpts opt helpCmds optBase i
51 |
52 | COMPREPLY=()
53 | cur=${COMP_WORDS[COMP_CWORD]}
54 |
55 | cmds=$_WSTOOL_BASE_COMMANDS
56 |
57 | if [[ $COMP_CWORD -eq 1 ]] ; then
58 | COMPREPLY=( $( compgen -W "$cmds" -- $cur ) )
59 | return 0
60 | fi
61 |
62 | # if not typing an option, or if the previous option required a
63 | # parameter, then fallback on ordinary filename expansion
64 | helpCmds='help|--help|h|\?'
65 | if [[ ${COMP_WORDS[1]} != @@($helpCmds) ]] && \
66 | [[ "$cur" != -* ]] ; then
67 | case ${COMP_WORDS[1]} in
68 | info|diff|di|status|st|remove|rm|update|up)
69 | cmdOpts=`wstool info --only=localname 2> /dev/null | sed 's,:, ,g'`
70 | COMPREPLY=( $( compgen -W "$cmdOpts" -- $cur ) )
71 | ;;
72 | set)
73 | if [[ $COMP_CWORD -eq 2 ]]; then
74 | cmdOpts=`wstool info --only=localname 2> /dev/null | sed 's,:, ,g'`
75 | COMPREPLY=( $( compgen -W "$cmdOpts" -- $cur ) )
76 | elif [[ $COMP_CWORD -eq 3 ]]; then
77 | cmdOpts=`wstool info ${COMP_WORDS[2]} --only=uri 2> /dev/null`
78 | COMPREPLY=( $( compgen -W "$cmdOpts" -- $cur ) )
79 | else
80 | if [[ ${COMP_WORDS[$(( $COMP_CWORD - 1 ))]} == "--version-new" ]]; then
81 | cmdOpts=`wstool info ${COMP_WORDS[2]} --only=version 2> /dev/null|sed 's/,$//'`
82 | COMPREPLY=( $( compgen -W "$cmdOpts" -- $cur ) )
83 | fi
84 | fi
85 | ;;
86 | esac
87 | return 0
88 | fi
89 |
90 | cmdOpts=
91 | case ${COMP_WORDS[1]} in
92 | status|st)
93 | cmdOpts="-t --target-workspace --untracked"
94 | ;;
95 | diff|di)
96 | cmdOpts="-t --target-workspace"
97 | ;;
98 | init)
99 | cmdOpts="-t --target-workspace --continue-on-error"
100 | ;;
101 | merge)
102 | cmdOpts="-t --target-workspace -y --confirm-all -r --merge-replace -k --merge-keep -a --merge-kill-append"
103 | ;;
104 | set)
105 | cmdOpts="-t --target-workspace --git --svn --bzr --hg --uri -v --version-new --detached -y --confirm"
106 | ;;
107 | remove|rm)
108 | cmdOpts="-t --target-workspace"
109 | ;;
110 | update|up)
111 | cmdOpts="-t --target-workspace --delete-changed-uris --abort-changed-uris --backup-changed-uris"
112 | ;;
113 | export)
114 | cmdOpts="-t --target-workspace -o --output --exact --spec"
115 | ;;
116 | info)
117 | cmdOpts="-t --target-workspace --data-only --no-pkg-path --pkg-path-only --only --yaml -u --untracked --fetch -s --short --root -m --managed-only"
118 | ;;
119 | *)
120 | ;;
121 | esac
122 |
123 | cmdOpts="$cmdOpts --help -h"
124 |
125 | # take out options already given
126 | for (( i=2; i<=$COMP_CWORD-1; ++i )) ; do
127 | opt=${COMP_WORDS[$i]}
128 |
129 | case $opt in
130 | --*) optBase=${opt/=*/} ;;
131 | -*) optBase=${opt:0:2} ;;
132 | esac
133 |
134 | cmdOpts=" $cmdOpts "
135 | cmdOpts=${cmdOpts/ ${optBase} / }
136 |
137 | # take out alternatives
138 | case $optBase in
139 | -h) cmdOpts=${cmdOpts/ --help / } ;;
140 | --help) cmdOpts=${cmdOpts/ -h / } ;;
141 | -t) cmdOpts=${cmdOpts/ --target-workspace / } ;;
142 | --target-workspace) cmdOpts=${cmdOpts/ -t / } ;;
143 | --delete-changed-uris)
144 | cmdOpts=${cmdOpts/ --abort-changed-uris / }
145 | cmdOpts=${cmdOpts/ --backup-changed-uris / }
146 | ;;
147 | --abort-changed-uris)
148 | cmdOpts=${cmdOpts/ --delete-changed-uris / }
149 | cmdOpts=${cmdOpts/ --backup-changed-uris / }
150 | ;;
151 | --backup-changed-uris)
152 | cmdOpts=${cmdOpts/ --delete-changed-uris / }
153 | cmdOpts=${cmdOpts/ --abort-changed-uris / }
154 | ;;
155 | # scm options
156 | --svn)
157 | cmdOpts=${cmdOpts/ --git / }
158 | cmdOpts=${cmdOpts/ --hg / }
159 | cmdOpts=${cmdOpts/ --bzr / }
160 | cmdOpts=${cmdOpts/ --detached / }
161 | ;;
162 | --git)
163 | cmdOpts=${cmdOpts/ --svn / }
164 | cmdOpts=${cmdOpts/ --hg / }
165 | cmdOpts=${cmdOpts/ --bzr / }
166 | cmdOpts=${cmdOpts/ --detached / }
167 | ;;
168 | --hg)
169 | cmdOpts=${cmdOpts/ --git / }
170 | cmdOpts=${cmdOpts/ --svn / }
171 | cmdOpts=${cmdOpts/ --bzr / }
172 | cmdOpts=${cmdOpts/ --detached / }
173 | ;;
174 | --bzr)
175 | cmdOpts=${cmdOpts/ --git / }
176 | cmdOpts=${cmdOpts/ --hg / }
177 | cmdOpts=${cmdOpts/ --svn / }
178 | cmdOpts=${cmdOpts/ --detached / }
179 | ;;
180 | --detached)
181 | cmdOpts=${cmdOpts/ --git / }
182 | cmdOpts=${cmdOpts/ --hg / }
183 | cmdOpts=${cmdOpts/ --bzr / }
184 | cmdOpts=${cmdOpts/ --svn / }
185 | ;;
186 | # merge options
187 | --merge-replace)
188 | cmdOpts=${cmdOpts/ --merge-keep / }
189 | cmdOpts=${cmdOpts/ --merge-kill-append / }
190 | cmdOpts=${cmdOpts/ -r / }
191 | cmdOpts=${cmdOpts/ -a / }
192 | cmdOpts=${cmdOpts/ -k / }
193 | ;;
194 | --merge-keep)
195 | cmdOpts=${cmdOpts/ --merge-replace / }
196 | cmdOpts=${cmdOpts/ --merge-kill-append / }
197 | cmdOpts=${cmdOpts/ -r / }
198 | cmdOpts=${cmdOpts/ -a / }
199 | cmdOpts=${cmdOpts/ -k / }
200 | ;;
201 | --merge-kill-append)
202 | cmdOpts=${cmdOpts/ --merge-keep / }
203 | cmdOpts=${cmdOpts/ --merge-replace / }
204 | cmdOpts=${cmdOpts/ -r / }
205 | cmdOpts=${cmdOpts/ -a / }
206 | cmdOpts=${cmdOpts/ -k / }
207 | ;;
208 | -r)
209 | cmdOpts=${cmdOpts/ --merge-keep / }
210 | cmdOpts=${cmdOpts/ --merge-kill-append / }
211 | cmdOpts=${cmdOpts/ --merge-replace / }
212 | cmdOpts=${cmdOpts/ -a / }
213 | cmdOpts=${cmdOpts/ -k / }
214 | ;;
215 | -a)
216 | cmdOpts=${cmdOpts/ --merge-keep / }
217 | cmdOpts=${cmdOpts/ --merge-kill-append / }
218 | cmdOpts=${cmdOpts/ --merge-replace / }
219 | cmdOpts=${cmdOpts/ -r / }
220 | cmdOpts=${cmdOpts/ -k / }
221 | ;;
222 | -k)
223 | cmdOpts=${cmdOpts/ --merge-keep / }
224 | cmdOpts=${cmdOpts/ --merge-kill-append / }
225 | cmdOpts=${cmdOpts/ --merge-replace / }
226 | cmdOpts=${cmdOpts/ -a / }
227 | cmdOpts=${cmdOpts/ -r / }
228 | ;;
229 | esac
230 |
231 | # skip next option if this one requires a parameter
232 | if [[ $opt == @@($optsParam) ]] ; then
233 | ((++i))
234 | fi
235 | done
236 |
237 | COMPREPLY=( $( compgen -W "$cmdOpts" -- $cur ) )
238 |
239 | return 0
240 |
241 | }
242 | complete -F _wstool_complete -o default wstool
243 |
--------------------------------------------------------------------------------
/doc/Makefile:
--------------------------------------------------------------------------------
1 | # Makefile for Sphinx documentation
2 | #
3 |
4 | # You can set these variables from the command line.
5 | SPHINXOPTS =
6 | SPHINXBUILD = sphinx-build
7 | PAPER =
8 | BUILDDIR = _build
9 |
10 | # User-friendly check for sphinx-build
11 | ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1)
12 | $(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/)
13 | endif
14 |
15 | # Internal variables.
16 | PAPEROPT_a4 = -D latex_paper_size=a4
17 | PAPEROPT_letter = -D latex_paper_size=letter
18 | ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
19 | # the i18n builder cannot share the environment and doctrees with the others
20 | I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
21 |
22 | .PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext
23 |
24 | help:
25 | @echo "Please use \`make ' where is one of"
26 | @echo " html to make standalone HTML files"
27 | @echo " dirhtml to make HTML files named index.html in directories"
28 | @echo " singlehtml to make a single large HTML file"
29 | @echo " pickle to make pickle files"
30 | @echo " json to make JSON files"
31 | @echo " htmlhelp to make HTML files and a HTML help project"
32 | @echo " qthelp to make HTML files and a qthelp project"
33 | @echo " devhelp to make HTML files and a Devhelp project"
34 | @echo " epub to make an epub"
35 | @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
36 | @echo " latexpdf to make LaTeX files and run them through pdflatex"
37 | @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx"
38 | @echo " text to make text files"
39 | @echo " man to make manual pages"
40 | @echo " texinfo to make Texinfo files"
41 | @echo " info to make Texinfo files and run them through makeinfo"
42 | @echo " gettext to make PO message catalogs"
43 | @echo " changes to make an overview of all changed/added/deprecated items"
44 | @echo " xml to make Docutils-native XML files"
45 | @echo " pseudoxml to make pseudoxml-XML files for display purposes"
46 | @echo " linkcheck to check all external links for integrity"
47 | @echo " doctest to run all doctests embedded in the documentation (if enabled)"
48 |
49 | clean:
50 | rm -rf $(BUILDDIR)/*
51 |
52 | html:
53 | $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
54 | @echo
55 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
56 |
57 | dirhtml:
58 | $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
59 | @echo
60 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
61 |
62 | singlehtml:
63 | $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
64 | @echo
65 | @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
66 |
67 | pickle:
68 | $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
69 | @echo
70 | @echo "Build finished; now you can process the pickle files."
71 |
72 | json:
73 | $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
74 | @echo
75 | @echo "Build finished; now you can process the JSON files."
76 |
77 | htmlhelp:
78 | $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
79 | @echo
80 | @echo "Build finished; now you can run HTML Help Workshop with the" \
81 | ".hhp project file in $(BUILDDIR)/htmlhelp."
82 |
83 | qthelp:
84 | $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
85 | @echo
86 | @echo "Build finished; now you can run "qcollectiongenerator" with the" \
87 | ".qhcp project file in $(BUILDDIR)/qthelp, like this:"
88 | @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/wstool.qhcp"
89 | @echo "To view the help file:"
90 | @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/wstool.qhc"
91 |
92 | devhelp:
93 | $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
94 | @echo
95 | @echo "Build finished."
96 | @echo "To view the help file:"
97 | @echo "# mkdir -p $$HOME/.local/share/devhelp/wstool"
98 | @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/wstool"
99 | @echo "# devhelp"
100 |
101 | epub:
102 | $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
103 | @echo
104 | @echo "Build finished. The epub file is in $(BUILDDIR)/epub."
105 |
106 | latex:
107 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
108 | @echo
109 | @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
110 | @echo "Run \`make' in that directory to run these through (pdf)latex" \
111 | "(use \`make latexpdf' here to do that automatically)."
112 |
113 | latexpdf:
114 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
115 | @echo "Running LaTeX files through pdflatex..."
116 | $(MAKE) -C $(BUILDDIR)/latex all-pdf
117 | @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
118 |
119 | latexpdfja:
120 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
121 | @echo "Running LaTeX files through platex and dvipdfmx..."
122 | $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja
123 | @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
124 |
125 | text:
126 | $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
127 | @echo
128 | @echo "Build finished. The text files are in $(BUILDDIR)/text."
129 |
130 | man:
131 | $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
132 | @echo
133 | @echo "Build finished. The manual pages are in $(BUILDDIR)/man."
134 |
135 | texinfo:
136 | $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
137 | @echo
138 | @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
139 | @echo "Run \`make' in that directory to run these through makeinfo" \
140 | "(use \`make info' here to do that automatically)."
141 |
142 | info:
143 | $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
144 | @echo "Running Texinfo files through makeinfo..."
145 | make -C $(BUILDDIR)/texinfo info
146 | @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
147 |
148 | gettext:
149 | $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
150 | @echo
151 | @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
152 |
153 | changes:
154 | $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
155 | @echo
156 | @echo "The overview file is in $(BUILDDIR)/changes."
157 |
158 | linkcheck:
159 | $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
160 | @echo
161 | @echo "Link check complete; look for any errors in the above output " \
162 | "or in $(BUILDDIR)/linkcheck/output.txt."
163 |
164 | doctest:
165 | $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
166 | @echo "Testing of doctests in the sources finished, look at the " \
167 | "results in $(BUILDDIR)/doctest/output.txt."
168 |
169 | upload: html
170 | # set write permission for group so that everybody can overwrite existing files on the webserver
171 | chmod -R g+w _build/html/
172 | scp -pr _build/html/ rosbot@ros.osuosl.org:/home/rosbot/docs/independent/api/wstool
173 |
174 | xml:
175 | $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml
176 | @echo
177 | @echo "Build finished. The XML files are in $(BUILDDIR)/xml."
178 |
179 | pseudoxml:
180 | $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml
181 | @echo
182 | @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml."
183 |
--------------------------------------------------------------------------------
/doc/changelog.rst:
--------------------------------------------------------------------------------
1 | Changelog
2 | =========
3 |
4 | 0.1.18
5 | ------
6 |
7 | - fix warnings by replacing yaml.load() with safe_load()
8 | - Re-add snapshot command called 'export' (#117, #120)
9 | - fix '-t' option not working for wstool remove
10 | - upgrade vcstools library version to 0.1.41, with new fixes:
11 |
12 | - fix git submodule errors
13 | - fix export_upstream for git submodules
14 | - fix python3 incompatibility
15 | - fix git fast-forward failures
16 | - fix get_affected_files
17 |
18 | 0.1.17
19 | ------
20 |
21 | - Reverted the snapshot command since it was breaking ``rosws`` until it can be fixed.
22 |
23 | 0.1.16
24 | ------
25 |
26 | - Fixed some issues with new ``requirements.txt`` usage during the release process.
27 |
28 | 0.1.15
29 | ------
30 |
31 | - Fixed an issue with the conditional dependency on ``ordereddict`` in the ``setup.py`` file.
32 |
33 | 0.1.14
34 | ------
35 |
36 | - Fixed an issue which caused a traceback with invalid command line options.
37 | - Added a feature to "snapshot" the current commit hashes in the workspace as a rosinstall file.
38 | - Fixed option handling and documentation of the ``--untracked`` option.
39 | - Added ``--shallow`` option to ``wstool init`` for shallow checkouts with git.
40 | - Contributors: @cbandera, @rsinnet, @amiller27, @jayvdb, @at-wat
41 |
42 | 0.1.13
43 | ------
44 |
45 | - Fix to avoid errors due to installing man pages with OS X's 10.11's new SIP settings.
46 | - Added option to show a simplified version info table.
47 | - Added the -m (timeout), -v (verbose), and -j (parallel jobs) options to each command.
48 | - Contributors: @NikolausDemmel, @wkentaro
49 |
50 | 0.1.12
51 | ------
52 |
53 | - Fix command line arguments of ``wstool scrape``.
54 |
55 | 0.1.11
56 | ------
57 |
58 | - Changed the way ``.bak`` files are created when overwriting existing configurations.
59 | - Added the Scrape command.
60 | - Added default git branch and status to ``wstool fetch --info``.
61 | - Added versioned dependency on vcstools ``0.1.38`` to make use of new API features.
62 |
63 | 0.1.10
64 | ------
65 |
66 | - Fix regression which broke the -j option.
67 | - Enable pretty printing of the ``.rosinstall`` file's YAML.
68 |
69 | 0.1.9
70 | -----
71 |
72 | - Fix for zsh completion.
73 | - Fixed version dependency on vcstools for debian.
74 |
75 | 0.1.8
76 | -----
77 |
78 | - Fix for installation issue.
79 |
80 | 0.1.7
81 | -----
82 |
83 | - Added installation of generated man pages.
84 | - Added installation of shell completion for wstool.
85 | - Improved output of wstool info with the new get_current_version_label in vcstools.
86 | - Added a foreach command.
87 | - Added a ``--root`` option to wstool info.
88 | - Enhanced the ``--update`` option for wstool set.
89 | - Now uses multiple threads for network operations by default.
90 | - Some other minor fixes and improvements and docs.
91 |
92 | 0.1.5
93 | -----
94 |
95 | - Releasing to allow changes for new platform vivid.
96 | - Fix svn diff for change in output with svn 1.7.9.
97 | - info command shows information about unmanaged paths.
98 |
99 | 0.1.4
100 | -----
101 |
102 | - Fix detection of path conflicts #24 (https://github.com/vcstools/wstool/pull/24).
103 |
104 | 0.0.3
105 | -----
106 |
107 | - not using ROS_WORKSPACE anymore
108 | - fix to "wstool cmd --help"
109 |
110 | 0.0.2
111 | -----
112 |
113 | - fix #2 creating "wstool2 file instaed of ".rosinstall"
114 |
115 | 0.0.1
116 | -----
117 |
118 | - Initial creation based on functions inrosinstall
119 |
--------------------------------------------------------------------------------
/doc/conf.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | #
3 | # wstool documentation build configuration file, created by
4 | # sphinx-quickstart on Tue Aug 11 08:44:18 2015.
5 | #
6 | # This file is execfile()d with the current directory set to its
7 | # containing dir.
8 | #
9 | # Note that not all possible configuration values are present in this
10 | # autogenerated file.
11 | #
12 | # All configuration values have a default; values that are commented out
13 | # serve to show the default.
14 |
15 | import sys
16 | import os
17 |
18 | import imp
19 |
20 | file = None
21 | try:
22 | file, pathname, description = imp.find_module('__version__', ['../src/wstool'])
23 | vermod = imp.load_module('__version__', file, pathname, description)
24 | version = vermod.version
25 | finally:
26 | if file is not None:
27 | file.close()
28 |
29 | # If extensions (or modules to document with autodoc) are in another directory,
30 | # add these directories to sys.path here. If the directory is relative to the
31 | # documentation root, use os.path.abspath to make it absolute, like shown here.
32 |
33 | # -- General configuration ------------------------------------------------
34 |
35 | # If your documentation needs a minimal Sphinx version, state it here.
36 | # needs_sphinx = '1.0'
37 |
38 | # Add any Sphinx extension module names here, as strings. They can be extensions
39 | # coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
40 | extensions = ['sphinx.ext.intersphinx']
41 |
42 | # Add any paths that contain templates here, relative to this directory.
43 | templates_path = ['_templates']
44 |
45 | # The suffix of source filenames.
46 | source_suffix = '.rst'
47 |
48 | # The encoding of source files.
49 | # source_encoding = 'utf-8-sig'
50 |
51 | # The master toctree document.
52 | master_doc = 'index'
53 |
54 | # General information about the project.
55 | project = u'wstool'
56 | copyright = u'2011, Willow Garage'
57 |
58 | # The version info for the project you're documenting, acts as replacement for
59 | # |version| and |release|, also used in various other places throughout the
60 | # built documents.
61 | #
62 | # The short X.Y version.
63 | version = version
64 | # The full version, including alpha/beta/rc tags.
65 | release = version
66 |
67 | # The language for content autogenerated by Sphinx. Refer to documentation
68 | # for a list of supported languages.
69 | # language = None
70 |
71 | # There are two options for replacing |today|: either, you set today to some
72 | # non-false value, then it is used:
73 | # today = ''
74 | # Else, today_fmt is used as the format for a strftime call.
75 | # today_fmt = '%B %d, %Y'
76 |
77 | # List of patterns, relative to source directory, that match files and
78 | # directories to ignore when looking for source files.
79 | exclude_patterns = ['_build']
80 |
81 | # The reST default role (used for this markup: `text`) to use for all documents.
82 | # default_role = None
83 |
84 | # If true, '()' will be appended to :func: etc. cross-reference text.
85 | # add_function_parentheses = True
86 |
87 | # If true, the current module name will be prepended to all description
88 | # unit titles (such as .. function::).
89 | # add_module_names = True
90 |
91 | # If true, sectionauthor and moduleauthor directives will be shown in the
92 | # output. They are ignored by default.
93 | # show_authors = False
94 |
95 | # The name of the Pygments (syntax highlighting) style to use.
96 | pygments_style = 'sphinx'
97 |
98 | # A list of ignored prefixes for module index sorting.
99 | # modindex_common_prefix = []
100 |
101 |
102 | # -- Options for HTML output ---------------------------------------------
103 |
104 | # The theme to use for HTML and HTML Help pages. See the documentation for
105 | # a list of builtin themes.
106 | html_theme = 'haiku'
107 |
108 | # Theme options are theme-specific and customize the look and feel of a theme
109 | # further. For a list of options available for each theme, see the
110 | # documentation.
111 | # html_theme_options = {}
112 |
113 | # Add any paths that contain custom themes here, relative to this directory.
114 | # html_theme_path = []
115 |
116 | # The name for this set of Sphinx documents. If None, it defaults to
117 | # " v documentation".
118 | # html_title = None
119 |
120 | # A shorter title for the navigation bar. Default is the same as html_title.
121 | # html_short_title = None
122 |
123 | # The name of an image file (relative to this directory) to place at the top
124 | # of the sidebar.
125 | # html_logo = None
126 |
127 | # The name of an image file (within the static path) to use as favicon of the
128 | # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
129 | # pixels large.
130 | # html_favicon = None
131 |
132 | # Add any paths that contain custom static files (such as style sheets) here,
133 | # relative to this directory. They are copied after the builtin static files,
134 | # so a file named "default.css" will overwrite the builtin "default.css".
135 | html_static_path = ['_static']
136 |
137 | # Add any extra paths that contain custom files (such as robots.txt or
138 | # .htaccess) here, relative to this directory. These files are copied
139 | # directly to the root of the documentation.
140 | #html_extra_path = []
141 |
142 | # If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
143 | # using the given strftime format.
144 | # html_last_updated_fmt = '%b %d, %Y'
145 |
146 | # If true, SmartyPants will be used to convert quotes and dashes to
147 | # typographically correct entities.
148 | # html_use_smartypants = True
149 |
150 | # Custom sidebar templates, maps document names to template names.
151 | # html_sidebars = {}
152 |
153 | # Additional templates that should be rendered to pages, maps page names to
154 | # template names.
155 | # html_additional_pages = {}
156 |
157 | # If false, no module index is generated.
158 | # html_domain_indices = True
159 |
160 | # If false, no index is generated.
161 | # html_use_index = True
162 |
163 | # If true, the index is split into individual pages for each letter.
164 | # html_split_index = False
165 |
166 | # If true, links to the reST sources are added to the pages.
167 | # html_show_sourcelink = True
168 |
169 | # If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
170 | # html_show_sphinx = True
171 |
172 | # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
173 | # html_show_copyright = True
174 |
175 | # If true, an OpenSearch description file will be output, and all pages will
176 | # contain a tag referring to it. The value of this option must be the
177 | # base URL from which the finished HTML is served.
178 | # html_use_opensearch = ''
179 |
180 | # This is the file name suffix for HTML files (e.g. ".xhtml").
181 | # html_file_suffix = None
182 |
183 | # Output file base name for HTML help builder.
184 | htmlhelp_basename = 'wstooldoc'
185 |
186 |
187 | # -- Options for LaTeX output ---------------------------------------------
188 |
189 | latex_elements = {
190 | # The paper size ('letterpaper' or 'a4paper').
191 | #'papersize': 'letterpaper',
192 |
193 | # The font size ('10pt', '11pt' or '12pt').
194 | #'pointsize': '10pt',
195 |
196 | # Additional stuff for the LaTeX preamble.
197 | #'preamble': '',
198 | }
199 |
200 | # Grouping the document tree into LaTeX files. List of tuples
201 | # (source start file, target name, title,
202 | # author, documentclass [howto, manual, or own class]).
203 | latex_documents = [
204 | ('index', 'wstool.tex', u'wstool Documentation',
205 | u'Tully Foote, Thibault Kruse, Ken Conley, Brian Gerkey', 'manual'),
206 | ]
207 |
208 | # The name of an image file (relative to this directory) to place at the top of
209 | # the title page.
210 | # latex_logo = None
211 |
212 | # For "manual" documents, if this is true, then toplevel headings are parts,
213 | # not chapters.
214 | # latex_use_parts = False
215 |
216 | # If true, show page references after internal links.
217 | # latex_show_pagerefs = False
218 |
219 | # If true, show URL addresses after external links.
220 | # latex_show_urls = False
221 |
222 | # Additional stuff for the LaTeX preamble.
223 | # latex_preamble = ''
224 |
225 | # Documents to append as an appendix to all manuals.
226 | # latex_appendices = []
227 |
228 | # If false, no module index is generated.
229 | # latex_domain_indices = True
230 |
231 |
232 | # -- Options for manual page output ---------------------------------------
233 |
234 | # One entry per manual page. List of tuples
235 | # (source start file, name, description, authors, manual section).
236 | man_pages = [
237 | ('index', 'wstool', u'wstool Documentation',
238 | [u'Tully Foote, Thibault Kruse, Ken Conley, Brian Gerkey'], 1)
239 | ]
240 |
241 | # If true, show URL addresses after external links.
242 | #man_show_urls = False
243 |
244 |
245 | # -- Options for Texinfo output -------------------------------------------
246 |
247 | # Grouping the document tree into Texinfo files. List of tuples
248 | # (source start file, target name, title, author,
249 | # dir menu entry, description, category)
250 | texinfo_documents = [
251 | ('index', 'wstool', u'wstool Documentation',
252 | u'Tully Foote, Thibault Kruse, Ken Conley, Brian Gerkey', 'wstool', 'One line description of project.',
253 | 'Miscellaneous'),
254 | ]
255 |
256 | # Documents to append as an appendix to all manuals.
257 | #texinfo_appendices = []
258 |
259 | # If false, no module index is generated.
260 | #texinfo_domain_indices = True
261 |
262 | # How to display URL addresses: 'footnote', 'no', or 'inline'.
263 | #texinfo_show_urls = 'footnote'
264 |
265 | # If true, do not generate a @detailmenu in the "Top" node's menu.
266 | #texinfo_no_detailmenu = False
267 |
268 |
269 | # Example configuration for intersphinx: refer to the Python standard library.
270 | intersphinx_mapping = {'http://docs.python.org/': None}
271 |
--------------------------------------------------------------------------------
/doc/developers_guide.rst:
--------------------------------------------------------------------------------
1 | Developer's Guide
2 | =================
3 |
4 | Changelog
5 | ---------
6 |
7 | .. toctree::
8 | :maxdepth: 1
9 |
10 | changelog
11 |
12 | Bug reports and feature requests
13 | --------------------------------
14 |
15 | - `Submit a bug report `_
16 |
17 | Developer Setup
18 | ---------------
19 |
20 | The wstool source can be downloaded using Mercurial::
21 |
22 | $ git clone https://github.com/vcstools/wstool.git
23 |
24 | You will also need vcstools, which you can either install using pip or download using::
25 |
26 | $ git clone https://github.com/vcstools/vcstools.git
27 | $ cd vcstools
28 | $ python develop
29 |
30 |
31 | wstool uses `setuptools `_,
32 | which you will need to download and install in order to run the
33 | packaging. We use setuptools instead of distutils in order to be able
34 | use ``setup()`` keys like ``install_requires``.
35 |
36 | Configure your environment:
37 |
38 | $ cd wstool
39 | $ python develop
40 |
41 | Testing
42 | -------
43 |
44 | Install test dependencies
45 |
46 | ::
47 |
48 | $ pip install nose
49 | $ pip install mock
50 |
51 |
52 | wstool uses `Python nose
53 | `_ for testing, which is
54 | a fairly simple and straightforward test framework. The wstool
55 | mainly use :mod:`unittest` to construct test fixtures, but with nose
56 | you can also just write a function that starts with the name ``test``
57 | and use normal ``assert`` statements.
58 |
59 | wstool also uses `mock `_
60 | to create mocks for testing.
61 |
62 | You can run the tests, including coverage, as follows:
63 |
64 | ::
65 |
66 | $ cd wstool
67 | $ make test
68 |
69 |
70 | Documentation
71 | -------------
72 |
73 | Sphinx is used to provide API documentation for wstool. The documents
74 | are stored in the ``doc`` sub-directory.
75 |
76 | You can build the docs as follows:
77 |
78 | ::
79 |
80 | $ cd wstool/doc
81 | $ make html
82 |
83 |
--------------------------------------------------------------------------------
/doc/index.rst:
--------------------------------------------------------------------------------
1 | wstool
2 | ======
3 |
4 | .. module:: wstool
5 | .. moduleauthor:: Tully Foote , Thibault Kruse , Ken Conley
6 |
7 | Using wstool you can update several folders using a variety
8 | of SCMs (SVN, Mercurial, git, Bazaar) with just one command.
9 |
10 | That way you can more effectively manage source code workspaces.
11 |
12 | The wstool package provides a Python API for interacting with a
13 | source code workspace as well as a group of command line tools.
14 | Rosinstall leverages the :mod:`vcstools` package for source control and
15 | stores its state in .rosinstall files.
16 |
17 |
18 | Command Line Tools:
19 | ===================
20 | .. toctree::
21 | :maxdepth: 2
22 |
23 | wstool_usage
24 |
25 |
26 | Installation
27 | ============
28 |
29 | Ubuntu
30 | ------
31 |
32 | On Ubuntu the recommended way to install rosinstall is to use apt.
33 |
34 | ::
35 |
36 | sudo apt-get install python-wstool
37 |
38 | Other Platforms
39 | ---------------
40 |
41 | On other platforms rosinstall is available on pypi and can be installed via ``pip``
42 | ::
43 |
44 | pip install -U wstool
45 |
46 | or ``easy_install``:
47 |
48 | ::
49 |
50 | easy_install -U wstool vcstools
51 |
52 |
53 |
54 |
55 | Rosinstall File Format:
56 | =======================
57 | .. toctree::
58 | :maxdepth: 2
59 |
60 | rosinstall_file_format
61 |
62 |
63 | Advanced: rosinstall developers/contributors
64 | ============================================
65 |
66 | .. toctree::
67 | :maxdepth: 2
68 |
69 | developers_guide
70 |
71 |
72 | Indices and tables
73 | ==================
74 |
75 | * :ref:`genindex`
76 | * :ref:`modindex`
77 | * :ref:`search`
78 |
--------------------------------------------------------------------------------
/doc/make.bat:
--------------------------------------------------------------------------------
1 | @ECHO OFF
2 |
3 | REM Command file for Sphinx documentation
4 |
5 | if "%SPHINXBUILD%" == "" (
6 | set SPHINXBUILD=sphinx-build
7 | )
8 | set BUILDDIR=build
9 | set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% source
10 | set I18NSPHINXOPTS=%SPHINXOPTS% source
11 | if NOT "%PAPER%" == "" (
12 | set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS%
13 | set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS%
14 | )
15 |
16 | if "%1" == "" goto help
17 |
18 | if "%1" == "help" (
19 | :help
20 | echo.Please use `make ^` where ^ is one of
21 | echo. html to make standalone HTML files
22 | echo. dirhtml to make HTML files named index.html in directories
23 | echo. singlehtml to make a single large HTML file
24 | echo. pickle to make pickle files
25 | echo. json to make JSON files
26 | echo. htmlhelp to make HTML files and a HTML help project
27 | echo. qthelp to make HTML files and a qthelp project
28 | echo. devhelp to make HTML files and a Devhelp project
29 | echo. epub to make an epub
30 | echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter
31 | echo. text to make text files
32 | echo. man to make manual pages
33 | echo. texinfo to make Texinfo files
34 | echo. gettext to make PO message catalogs
35 | echo. changes to make an overview over all changed/added/deprecated items
36 | echo. xml to make Docutils-native XML files
37 | echo. pseudoxml to make pseudoxml-XML files for display purposes
38 | echo. linkcheck to check all external links for integrity
39 | echo. doctest to run all doctests embedded in the documentation if enabled
40 | goto end
41 | )
42 |
43 | if "%1" == "clean" (
44 | for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i
45 | del /q /s %BUILDDIR%\*
46 | goto end
47 | )
48 |
49 |
50 | %SPHINXBUILD% 2> nul
51 | if errorlevel 9009 (
52 | echo.
53 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
54 | echo.installed, then set the SPHINXBUILD environment variable to point
55 | echo.to the full path of the 'sphinx-build' executable. Alternatively you
56 | echo.may add the Sphinx directory to PATH.
57 | echo.
58 | echo.If you don't have Sphinx installed, grab it from
59 | echo.http://sphinx-doc.org/
60 | exit /b 1
61 | )
62 |
63 | if "%1" == "html" (
64 | %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html
65 | if errorlevel 1 exit /b 1
66 | echo.
67 | echo.Build finished. The HTML pages are in %BUILDDIR%/html.
68 | goto end
69 | )
70 |
71 | if "%1" == "dirhtml" (
72 | %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml
73 | if errorlevel 1 exit /b 1
74 | echo.
75 | echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml.
76 | goto end
77 | )
78 |
79 | if "%1" == "singlehtml" (
80 | %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml
81 | if errorlevel 1 exit /b 1
82 | echo.
83 | echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml.
84 | goto end
85 | )
86 |
87 | if "%1" == "pickle" (
88 | %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle
89 | if errorlevel 1 exit /b 1
90 | echo.
91 | echo.Build finished; now you can process the pickle files.
92 | goto end
93 | )
94 |
95 | if "%1" == "json" (
96 | %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json
97 | if errorlevel 1 exit /b 1
98 | echo.
99 | echo.Build finished; now you can process the JSON files.
100 | goto end
101 | )
102 |
103 | if "%1" == "htmlhelp" (
104 | %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp
105 | if errorlevel 1 exit /b 1
106 | echo.
107 | echo.Build finished; now you can run HTML Help Workshop with the ^
108 | .hhp project file in %BUILDDIR%/htmlhelp.
109 | goto end
110 | )
111 |
112 | if "%1" == "qthelp" (
113 | %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp
114 | if errorlevel 1 exit /b 1
115 | echo.
116 | echo.Build finished; now you can run "qcollectiongenerator" with the ^
117 | .qhcp project file in %BUILDDIR%/qthelp, like this:
118 | echo.^> qcollectiongenerator %BUILDDIR%\qthelp\wstool.qhcp
119 | echo.To view the help file:
120 | echo.^> assistant -collectionFile %BUILDDIR%\qthelp\wstool.ghc
121 | goto end
122 | )
123 |
124 | if "%1" == "devhelp" (
125 | %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp
126 | if errorlevel 1 exit /b 1
127 | echo.
128 | echo.Build finished.
129 | goto end
130 | )
131 |
132 | if "%1" == "epub" (
133 | %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub
134 | if errorlevel 1 exit /b 1
135 | echo.
136 | echo.Build finished. The epub file is in %BUILDDIR%/epub.
137 | goto end
138 | )
139 |
140 | if "%1" == "latex" (
141 | %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
142 | if errorlevel 1 exit /b 1
143 | echo.
144 | echo.Build finished; the LaTeX files are in %BUILDDIR%/latex.
145 | goto end
146 | )
147 |
148 | if "%1" == "latexpdf" (
149 | %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
150 | cd %BUILDDIR%/latex
151 | make all-pdf
152 | cd %BUILDDIR%/..
153 | echo.
154 | echo.Build finished; the PDF files are in %BUILDDIR%/latex.
155 | goto end
156 | )
157 |
158 | if "%1" == "latexpdfja" (
159 | %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
160 | cd %BUILDDIR%/latex
161 | make all-pdf-ja
162 | cd %BUILDDIR%/..
163 | echo.
164 | echo.Build finished; the PDF files are in %BUILDDIR%/latex.
165 | goto end
166 | )
167 |
168 | if "%1" == "text" (
169 | %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text
170 | if errorlevel 1 exit /b 1
171 | echo.
172 | echo.Build finished. The text files are in %BUILDDIR%/text.
173 | goto end
174 | )
175 |
176 | if "%1" == "man" (
177 | %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man
178 | if errorlevel 1 exit /b 1
179 | echo.
180 | echo.Build finished. The manual pages are in %BUILDDIR%/man.
181 | goto end
182 | )
183 |
184 | if "%1" == "texinfo" (
185 | %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo
186 | if errorlevel 1 exit /b 1
187 | echo.
188 | echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo.
189 | goto end
190 | )
191 |
192 | if "%1" == "gettext" (
193 | %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale
194 | if errorlevel 1 exit /b 1
195 | echo.
196 | echo.Build finished. The message catalogs are in %BUILDDIR%/locale.
197 | goto end
198 | )
199 |
200 | if "%1" == "changes" (
201 | %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes
202 | if errorlevel 1 exit /b 1
203 | echo.
204 | echo.The overview file is in %BUILDDIR%/changes.
205 | goto end
206 | )
207 |
208 | if "%1" == "linkcheck" (
209 | %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck
210 | if errorlevel 1 exit /b 1
211 | echo.
212 | echo.Link check complete; look for any errors in the above output ^
213 | or in %BUILDDIR%/linkcheck/output.txt.
214 | goto end
215 | )
216 |
217 | if "%1" == "doctest" (
218 | %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest
219 | if errorlevel 1 exit /b 1
220 | echo.
221 | echo.Testing of doctests in the sources finished, look at the ^
222 | results in %BUILDDIR%/doctest/output.txt.
223 | goto end
224 | )
225 |
226 | if "%1" == "xml" (
227 | %SPHINXBUILD% -b xml %ALLSPHINXOPTS% %BUILDDIR%/xml
228 | if errorlevel 1 exit /b 1
229 | echo.
230 | echo.Build finished. The XML files are in %BUILDDIR%/xml.
231 | goto end
232 | )
233 |
234 | if "%1" == "pseudoxml" (
235 | %SPHINXBUILD% -b pseudoxml %ALLSPHINXOPTS% %BUILDDIR%/pseudoxml
236 | if errorlevel 1 exit /b 1
237 | echo.
238 | echo.Build finished. The pseudo-XML files are in %BUILDDIR%/pseudoxml.
239 | goto end
240 | )
241 |
242 | :end
243 |
--------------------------------------------------------------------------------
/doc/rosinstall_file_format.rst:
--------------------------------------------------------------------------------
1 | rosinstall file format
2 | ======================
3 |
4 | Format
5 | ------
6 |
7 | The rosinstall file format is a yaml document. It is a list of
8 | top level dictionaries. Each top level dictionary is expected to have one of the vcs type keys and no other keys.
9 |
10 | 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.
11 |
12 | Each of the vcs type keys requires a ``uri`` key, and optionally takes a ``version`` key.
13 |
14 | Top Level Keys
15 | --------------
16 | The valid keys are ``svn``, ``hg``, ``git``, ``bzr``.
17 |
18 | Each key represents a form of version control system to use. These are supported from the vcstools module.
19 |
20 | Example rosinstall syntax:
21 | --------------------------
22 |
23 | Below is an example rosinstall syntax with examples of most of the
24 | possible permutations:
25 |
26 | ::
27 |
28 | - svn: {local-name: some/local/path2, uri: /some/local/uri}
29 | - hg: {local-name: some/local/path3, uri: http://some/uri, version: 123}
30 | - git: {local-name: /some/local/aboslute/path, uri: http://some/uri, version: 123}
31 | - bzr: {local-name: some/local/path4, uri: http://some/uri, version: 123}
32 |
33 | Things to note are:
34 |
35 | - ``version`` is optional though recommended.
36 | - Absolute or relative paths are valid for ``local-name``
37 | - ``uri`` can be a local file path to a repository.
38 |
--------------------------------------------------------------------------------
/doc/wstool_usage.rst:
--------------------------------------------------------------------------------
1 | wstool: A tool for managing source code workspaces
2 | ==================================================
3 |
4 | wstool allows manipulation of a set of version-controlled folders as
5 | specified in a workspace definition file.
6 |
7 | .. contents:: Contents
8 | :depth: 3
9 |
10 |
11 | Usage
12 | -----
13 |
14 | ::
15 |
16 | wstool is a command to manipulate multiple version controlled folders.
17 |
18 | Official usage:
19 | wstool CMD [ARGS] [OPTIONS]
20 |
21 | wstool will try to infer install path from context
22 |
23 | Type 'wstool help' for usage.
24 | Options:
25 | help provide help for commands
26 | init set up a directory as workspace
27 | set add or changes one entry from your workspace config
28 | merge merges your workspace with another config set
29 | remove (rm) remove an entry from your workspace config, without deleting files
30 | update (up) update or check out some of your config elements
31 | info Overview of some entries
32 | status (st) print the change status of files in some SCM controlled entries
33 | diff (di) print a diff over some SCM controlled entries
34 |
35 |
36 | init
37 | ~~~~
38 |
39 | set up a directory as workspace
40 |
41 | wstool init does the following:
42 |
43 | 1. Reads folder/file/web-uri SOURCE_PATH looking for a rosinstall yaml
44 | 2. Creates new .rosinstall file at TARGET-PATH configured
45 |
46 | SOURCE_PATH can e.g. be a folder like /opt/ros/electric
47 | If PATH is not given, uses current folder.
48 |
49 | ::
50 |
51 | Usage: wstool init [TARGET_PATH [SOURCE_PATH]]?
52 |
53 | Options::
54 |
55 | -h, --help show this help message and exit
56 | --continue-on-error Continue despite checkout errors
57 | -j JOBS, --parallel=JOBS
58 | How many parallel threads to use for installing
59 |
60 | Examples::
61 |
62 | $ wstool init ~/jade /opt/ros/jade
63 |
64 |
65 | set
66 | ~~~
67 |
68 | add or changes one entry from your workspace config
69 | The command will infer whether you want to add or modify an entry. If
70 | you modify, it will only change the details you provide, keeping
71 | those you did not provide. if you only provide a uri, will use the
72 | basename of it as localname unless such an element already exists.
73 |
74 | The command only changes the configuration, to checkout or update
75 | the element, run wstool update afterwards.
76 |
77 | ::
78 |
79 | Usage: wstool set [localname] [SCM-URI]? [--(detached|svn|hg|git|bzr)] [--version=VERSION]]
80 |
81 | Options:
82 | -h, --help show this help message and exit
83 | --detached make an entry unmanaged (default for new element)
84 | -v VERSION, --version-new=VERSION
85 | point SCM to this version
86 | --git make an entry a git entry
87 | --svn make an entry a subversion entry
88 | --hg make an entry a mercurial entry
89 | --bzr make an entry a bazaar entry
90 | -y, --confirm Do not ask for confirmation
91 | -u, --update update repository after set
92 | -t WORKSPACE, --target-workspace=WORKSPACE
93 | which workspace to use
94 |
95 | Examples::
96 |
97 | $ wstool set robot_model --hg https://kforge.ros.org/robotmodel/robot_model
98 | $ wstool set robot_model --version robot_model-1.7.1
99 | $ wstool set robot_model --detached
100 |
101 |
102 |
103 | merge
104 | ~~~~~
105 |
106 | The command merges config with given other rosinstall element sets, from files
107 | or web uris.
108 |
109 | The default workspace will be inferred from context, you can specify one using
110 | -t.
111 |
112 | By default, when an element in an additional URI has the same
113 | local-name as an existing element, the existing element will be
114 | replaced. In order to ensure the ordering of elements is as
115 | provided in the URI, use the option ``--merge-kill-append``.
116 |
117 | ::
118 |
119 | Usage: wstool merge [URI] [OPTIONS]
120 |
121 | Options:
122 | -h, --help show this help message and exit
123 | -a, --merge-kill-append
124 | merge by deleting given entry and appending new one
125 | -k, --merge-keep (default) merge by keeping existing entry and
126 | discarding new one
127 | -r, --merge-replace merge by replacing given entry with new one
128 | maintaining ordering
129 | -y, --confirm-all do not ask for confirmation unless strictly necessary
130 | -t WORKSPACE, --target-workspace=WORKSPACE
131 | which workspace to use
132 |
133 | Examples::
134 |
135 | $ wstool merge someother.rosinstall
136 |
137 | You can use '-' to pipe in input, as an example::
138 |
139 | $ roslocate info robot_mode | wstool merge -
140 |
141 |
142 | update
143 | ~~~~~~
144 |
145 | update or check out some of your config elements
146 |
147 | This command calls the SCM provider to pull changes from remote to
148 | your local filesystem. In case the url has changed, the command will
149 | ask whether to delete or backup the folder.
150 |
151 | ::
152 |
153 | Usage: wstool update [localname]*
154 |
155 | Options:
156 | -h, --help show this help message and exit
157 | --delete-changed-uris
158 | Delete the local copy of a directory before changing
159 | uri.
160 | --abort-changed-uris Abort if changed uri detected
161 | --continue-on-error Continue despite checkout errors
162 | --backup-changed-uris=BACKUP_CHANGED
163 | backup the local copy of a directory before changing
164 | uri to this directory.
165 | -j JOBS, --parallel=JOBS
166 | How many parallel threads to use for installing
167 | -v, --verbose Whether to print out more information
168 | -t WORKSPACE, --target-workspace=WORKSPACE
169 | which workspace to use
170 |
171 |
172 | Examples::
173 |
174 | $ wstool update -t ~/jade
175 | $ wstool update robot_model geometry
176 |
177 |
178 |
179 | info
180 | ~~~~
181 |
182 | Overview of some entries
183 |
184 | The Status (S) column shows
185 | x for missing
186 | L for uncommited (local) changes
187 | V for difference in version and/or remote URI
188 | C for difference in local and remote versions
189 |
190 | The 'Version-Spec' column shows what tag, branch or revision was given
191 | in the .rosinstall file. The 'UID' column shows the unique ID of the
192 | current (and specified) version. The 'URI' column shows the configured
193 | URL of the repo.
194 |
195 | If status is V, the difference between what was specified and what is
196 | real is shown in the respective column. For SVN entries, the url is
197 | split up according to standard layout (trunk/tags/branches). The
198 | ROS_PACKAGE_PATH follows the order of the table, earlier entries
199 | overlay later entries.
200 |
201 | When given one localname, just show the data of one element in list
202 | form.
203 | This also has the generic properties element which is usually empty.
204 |
205 | The ``--only`` option accepts keywords: ['path', 'localname', 'version',
206 | 'revision', 'cur_revision', 'uri', 'cur_uri', 'scmtype']
207 |
208 | ::
209 |
210 | Usage: wstool info [localname]* [OPTIONS]
211 |
212 |
213 | Options:
214 | -h, --help show this help message and exit
215 | --root Show workspace root path
216 | --data-only Does not provide explanations
217 | --only=ONLY Shows comma-separated lists of only given comma-
218 | separated attribute(s).
219 | --yaml Shows only version of single entry. Intended for
220 | scripting.
221 | --fetch When used, retrieves version information from remote
222 | (takes longer).
223 | -u, --untracked Also show untracked files as modifications
224 | -t WORKSPACE, --target-workspace=WORKSPACE
225 | which workspace to use
226 | -m, --managed-only only show managed elements
227 |
228 | Examples::
229 |
230 | $ wstool info -t ~/ros/jade
231 | $ wstool info robot_model
232 | $ wstool info --yaml
233 | $ wstool info --only=path,cur_uri,cur_revision robot_model geometry
234 |
235 |
236 |
237 |
238 | status
239 | ~~~~~~
240 |
241 | print the change status of files in some SCM controlled entries. The status
242 | columns meanings are as the respective SCM defines them.
243 |
244 | ::
245 |
246 | Usage: wstool status [localname]*
247 |
248 | Options:
249 | -h, --help show this help message and exit
250 | -u, --untracked Also shows untracked files
251 | -t WORKSPACE, --target-workspace=WORKSPACE
252 | which workspace to use
253 |
254 | diff
255 | ~~~~
256 |
257 | print a diff over some SCM controlled entries
258 |
259 | ::
260 |
261 | Usage: wstool diff [localname]*
262 |
263 | Options:
264 | -h, --help show this help message and exit
265 | -t WORKSPACE, --target-workspace=WORKSPACE
266 | which workspace to use
267 |
--------------------------------------------------------------------------------
/requirements-test.txt:
--------------------------------------------------------------------------------
1 | nose
2 | mock
3 | pep8
4 | # run checks in multiple environments
5 | tox
6 | tox-pyenv
7 |
8 | coverage~=4.5
9 | coveralls
10 |
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | vcstools>=0.1.42
2 | pyyaml
3 |
--------------------------------------------------------------------------------
/scripts/wstool:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # Software License Agreement (BSD License)
3 | #
4 | # Copyright (c) 2010, Willow Garage, Inc.
5 | # All rights reserved.
6 | #
7 | # Redistribution and use in source and binary forms, with or without
8 | # modification, are permitted provided that the following conditions
9 | # are met:
10 | #
11 | # * Redistributions of source code must retain the above copyright
12 | # notice, this list of conditions and the following disclaimer.
13 | # * Redistributions in binary form must reproduce the above
14 | # copyright notice, this list of conditions and the following
15 | # disclaimer in the documentation and/or other materials provided
16 | # with the distribution.
17 | # * Neither the name of Willow Garage, Inc. nor the names of its
18 | # contributors may be used to endorse or promote products derived
19 | # from this software without specific prior written permission.
20 | #
21 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 | # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 | # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24 | # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25 | # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26 | # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 | # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 | # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29 | # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 | # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31 | # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32 | # POSSIBILITY OF SUCH DAMAGE.
33 | #
34 | # Revision $Id: rosws 14389 2011-07-20 18:38:40Z tfoote $
35 | # $Author: tfoote $
36 |
37 | """%(prog)s is a command to manipulate ROS workspaces.
38 |
39 | Official usage:
40 | %(prog)s CMD [ARGS] [OPTIONS]
41 |
42 | %(prog)s will try to infer install path from context
43 | "%(prog)s init" replaces the rosinstall command
44 |
45 | Type '%(prog)s --help' for usage.
46 | """
47 |
48 | from __future__ import print_function
49 | import sys
50 |
51 | try:
52 | import wstool.wstool_cli
53 | from wstool.common import MultiProjectException
54 | except ImportError as exc:
55 | sys.exit("ERROR: Cannot find required rosinstall library version, \
56 | check your installation (also of vcstools) is up-to-date. One frequent cause \
57 | is that rosinstall 0.5 is still installed in /usr/local/lib.\n%s" % exc)
58 |
59 |
60 | if __name__ == "__main__":
61 | try:
62 | sys.exit(wstool.wstool_cli.wstool_main(sys.argv))
63 | except MultiProjectException as mpe:
64 | sys.exit("ERROR in config: %s" % str(mpe))
65 |
--------------------------------------------------------------------------------
/setup.cfg:
--------------------------------------------------------------------------------
1 | [bdist_wheel]
2 | universal = 1
3 |
4 | [aliases]
5 | test = nosetests --with-coverage --cover-package=wstool --where=test --cover-min-percentage=80
6 |
--------------------------------------------------------------------------------
/setup.py:
--------------------------------------------------------------------------------
1 | from setuptools import setup
2 | from distutils.command.build import build
3 | from distutils.command.build_py import build_py
4 |
5 | import os
6 | import sys
7 | import imp
8 | import argparse
9 |
10 |
11 | with open('README.rst') as readme_file:
12 | README = readme_file.read()
13 |
14 |
15 | def get_version():
16 | ver_file = None
17 | try:
18 | ver_file, pathname, description = imp.find_module('__version__', ['src/wstool'])
19 | vermod = imp.load_module('__version__', ver_file, pathname, description)
20 | version = vermod.version
21 | return version
22 | finally:
23 | if ver_file is not None:
24 | ver_file.close()
25 |
26 |
27 | def _resolve_prefix(prefix, type):
28 | # install to outside of system if OS X to avoid issues caused by
29 | # System Integrity Protection on El Caption
30 | # issue: https://github.com/vcstools/wstool/issues/81
31 | osx_system_prefix = '/System/Library/Frameworks/Python.framework/Versions'
32 | if type == 'man':
33 | if prefix == '/usr':
34 | return '/usr/share'
35 | if sys.prefix.startswith(osx_system_prefix):
36 | return '/usr/local/share'
37 | elif type == 'bash_comp':
38 | if prefix == '/usr':
39 | return '/'
40 | if sys.prefix.startswith(osx_system_prefix):
41 | return '/usr/local'
42 | elif type == 'zsh_comp':
43 | if sys.prefix.startswith(osx_system_prefix):
44 | return '/usr/local'
45 | else:
46 | raise ValueError('not supported type')
47 | return prefix
48 |
49 |
50 | def get_data_files(prefix):
51 | data_files = []
52 | bash_comp_dest = os.path.join(_resolve_prefix(prefix, 'bash_comp'),
53 | 'etc/bash_completion.d')
54 | data_files.append((bash_comp_dest, ['completion/wstool-completion.bash']))
55 | zsh_comp_dest = os.path.join(_resolve_prefix(prefix, 'zsh_comp'),
56 | 'share/zsh/site-functions')
57 | data_files.append((zsh_comp_dest, ['completion/_wstool',
58 | 'completion/wstool-completion.bash']))
59 | return data_files
60 |
61 |
62 | parser = argparse.ArgumentParser()
63 | parser.add_argument('--prefix', default=None,
64 | help='prefix to install data files')
65 | opts, _ = parser.parse_known_args(sys.argv)
66 | prefix = sys.prefix if opts.prefix == None else opts.prefix
67 |
68 | data_files = get_data_files(prefix)
69 |
70 | # At present setuptools has no methods to resolve dependencies at build time,
71 | # so we need to check if sphinx is installed.
72 | # See: https://github.com/pypa/pip/issues/2381
73 | try:
74 | from sphinx.setup_command import BuildDoc
75 | HAVE_SPHINX = True
76 | except:
77 | HAVE_SPHINX = False
78 |
79 | if HAVE_SPHINX:
80 | class WstoolBuildMan(BuildDoc):
81 | def initialize_options(self):
82 | BuildDoc.initialize_options(self)
83 | self.builder = 'man'
84 |
85 | class WstoolBuild(build):
86 | """Run additional commands before build command"""
87 | def run(self):
88 | self.run_command('build_man')
89 | build.run(self)
90 |
91 | class WstoolBuildPy(build_py):
92 | """Run additional commands before build_py command"""
93 | def run(self):
94 | self.run_command('build_man')
95 | build_py.run(self)
96 | cmdclass = dict(
97 | build=WstoolBuild,
98 | build_py=WstoolBuildPy,
99 | build_man=WstoolBuildMan,
100 | )
101 | man_dest = os.path.join(_resolve_prefix(prefix, 'man'), 'man/man1')
102 | data_files.append((man_dest, ['build/sphinx/man/wstool.1']))
103 | else:
104 | cmdclass = {}
105 |
106 | with open(os.path.join(os.path.dirname(__file__), 'requirements.txt')) as requirements:
107 | install_requires = requirements.read().splitlines()
108 |
109 | with open(os.path.join(os.path.dirname(__file__), 'requirements-test.txt')) as requirements:
110 | test_required = requirements.read().splitlines()
111 |
112 | setup(name='wstool',
113 | version=get_version(),
114 | packages=['wstool'],
115 | package_dir={'': 'src'},
116 | data_files=data_files,
117 | cmdclass=cmdclass,
118 | # rosinstall dependency to be kept in order not to break ros hydro install instructions
119 | install_requires=install_requires,
120 | # extras_require allow pip install .[test]
121 | extras_require={
122 | 'test': test_required
123 | },
124 | # tests_require automatically installed when running python setup.py test
125 | tests_require=test_required,
126 | scripts=["scripts/wstool"],
127 | author="Tully Foote",
128 | author_email="tfoote@osrfoundation.org",
129 | url="http://wiki.ros.org/wstool",
130 | keywords=["ROS"],
131 | classifiers=["Programming Language :: Python",
132 | "Programming Language :: Python :: 2",
133 | "Programming Language :: Python :: 3",
134 | "Development Status :: 7 - Inactive",
135 | "License :: OSI Approved :: BSD License",
136 | "Topic :: Software Development :: Version Control"
137 | ],
138 | description="workspace multi-SCM commands",
139 | long_description=README,
140 | license="BSD")
141 |
--------------------------------------------------------------------------------
/src/wstool/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vcstools/wstool/7f74a7997c7dee7c856516cbb4c59c15e2f72fee/src/wstool/__init__.py
--------------------------------------------------------------------------------
/src/wstool/__version__.py:
--------------------------------------------------------------------------------
1 | version = '0.1.18'
2 |
--------------------------------------------------------------------------------
/src/wstool/config.py:
--------------------------------------------------------------------------------
1 | # Software License Agreement (BSD License)
2 | #
3 | # Copyright (c) 2009, Willow Garage, Inc.
4 | # All rights reserved.
5 | #
6 | # Redistribution and use in source and binary forms, with or without
7 | # modification, are permitted provided that the following conditions
8 | # are met:
9 | #
10 | # * Redistributions of source code must retain the above copyright
11 | # notice, this list of conditions and the following disclaimer.
12 | # * Redistributions in binary form must reproduce the above
13 | # copyright notice, this list of conditions and the following
14 | # disclaimer in the documentation and/or other materials provided
15 | # with the distribution.
16 | # * Neither the name of Willow Garage, Inc. nor the names of its
17 | # contributors may be used to endorse or promote products derived
18 | # from this software without specific prior written permission.
19 | #
20 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 | # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 | # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 | # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 | # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 | # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 | # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 | # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 | # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 | # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 | # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 | # POSSIBILITY OF SUCH DAMAGE.
32 |
33 |
34 | import os
35 | from wstool.config_elements import AVCSConfigElement, OtherConfigElement, SetupConfigElement
36 | from wstool.common import MultiProjectException, normabspath, realpath_relation, normalize_uri
37 |
38 |
39 | class Config:
40 | """
41 | A config is a set of config elements, each of which defines a folder or file
42 | and possibly a VCS from which to update the folder.
43 | """
44 |
45 | def __init__(self, path_specs, install_path, config_filename=None, extended_types=None, merge_strategy='KillAppend'):
46 | """
47 | :param config_source_dict: A list (e.g. from yaml) describing the config, list of dict, each dict describing one element.
48 | :param config_filename: When given a folder, Config
49 | :param merge_strategy: how to deal with entries with equivalent path. See insert_element
50 |
51 | will look in folder for file of that name for more config source, str.
52 | """
53 | assert install_path is not None, "Install path is None"
54 | if path_specs is None:
55 | raise MultiProjectException("Passed empty source to create config")
56 | # All API operations must grant that elements in trees have unique local_name and paths
57 | # Also managed (VCS) entries must be disjunct (meaning one cannot be in a child folder of another managed one)
58 | # The idea is that managed entries can safely be concurrently modified
59 | self.trees = []
60 | self.base_path = os.path.abspath(install_path)
61 |
62 | self.config_filename = None
63 | if config_filename is not None:
64 | self.config_filename = os.path.basename(config_filename)
65 | # using a registry primarily for unit test design
66 | self.registry = {'svn': AVCSConfigElement,
67 | 'git': AVCSConfigElement,
68 | 'hg': AVCSConfigElement,
69 | 'bzr': AVCSConfigElement,
70 | 'tar': AVCSConfigElement}
71 | if extended_types is not None:
72 | self.registry = dict(list(self.registry.items()) + list(extended_types.items()))
73 |
74 | for path_spec in path_specs:
75 | action = self.add_path_spec(path_spec, merge_strategy)
76 | # Usual action in init should be 'Append', anything else is unusual
77 | if action == 'KillAppend':
78 | print("Replace existing entry %s by appending." % path_spec.get_local_name())
79 | elif action == 'MergeReplace':
80 | print("Replace existing entry %s" % path_spec.get_local_name())
81 | elif action == 'MergeKeep':
82 | print("Keep existing entry %s, discard later one" % path_spec.get_local_name())
83 |
84 | def __str__(self):
85 | return str([str(x) for x in self.trees])
86 |
87 | def add_path_spec(self, path_spec, merge_strategy='KillAppend'):
88 | """
89 | add new element to this config with information provided in path spec
90 |
91 | :param merge_strategy: see insert_element
92 | :param path_specs: PathSpec objects
93 | :returns: merge action taken, see insert_element
94 | """
95 | # compute the local_path for the config element
96 | local_path = normabspath(
97 | path_spec.get_local_name(), self.get_base_path())
98 | if os.path.isfile(local_path):
99 | if path_spec.get_tags() is not None and 'setup-file' in path_spec.get_tags():
100 | elem = SetupConfigElement(local_path,
101 | os.path.normpath(path_spec.get_local_name()),
102 | properties=path_spec.get_tags())
103 | return self.insert_element(elem, merge_strategy)
104 | else:
105 | print("!!!!! Warning: Not adding file %s" % local_path)
106 | return None
107 | else:
108 | # scmtype == None kept for historic reasons here
109 | if (path_spec.get_scmtype() == None and
110 | self.config_filename is not None and
111 | os.path.exists(os.path.join(local_path, self.config_filename))):
112 |
113 | print("!!!!! Warning: Not recursing into other config folder %s containing file %s" % (local_path, self.config_filename))
114 | return None
115 |
116 | if path_spec.get_scmtype() != None:
117 | return self._insert_vcs_path_spec(path_spec, local_path, merge_strategy)
118 | else:
119 | # keep the given local name (e.g. relative path) for other
120 | # elements, but normalize
121 | local_name = os.path.normpath(path_spec.get_local_name())
122 | elem = OtherConfigElement(local_path,
123 | local_name,
124 | path_spec.get_uri(),
125 | path_spec.get_version(),
126 | properties=path_spec.get_tags())
127 | return self.insert_element(elem, merge_strategy)
128 |
129 | def _insert_vcs_path_spec(self, path_spec, local_path, merge_strategy='KillAppend'):
130 | # Get the version and source_uri elements
131 | source_uri = normalize_uri(path_spec.get_uri(), self.get_base_path())
132 |
133 | version = path_spec.get_version()
134 | try:
135 | local_name = os.path.normpath(path_spec.get_local_name())
136 | elem = self._create_vcs_config_element(
137 | path_spec.get_scmtype(),
138 | local_path,
139 | local_name,
140 | source_uri,
141 | version,
142 | properties=path_spec.get_tags())
143 | return self.insert_element(elem, merge_strategy)
144 | except LookupError as ex:
145 | raise MultiProjectException(
146 | "Abstracted VCS Config failed. Exception: %s" % ex)
147 |
148 | def insert_element(self, new_config_elt, merge_strategy='KillAppend'):
149 | """
150 | Insert ConfigElement to self.trees, checking for duplicate
151 | local-name or path first. In case local_name matches, follow
152 | given strategy
153 |
154 | - KillAppend (default): remove old element, append new at the end
155 | - MergeReplace: remove first hit, insert new at that position.
156 | - MergeKeep: Discard new element
157 |
158 | In case local path matches but local name does not, raise Exception
159 |
160 | :returns: the action performed None, 'Append', 'KillAppend',
161 | 'MergeReplace', 'MergeKeep'
162 | """
163 | removals = []
164 | replaced = False
165 | for index, loop_elt in enumerate(self.trees):
166 | # if paths are os.path.realpath, no symlink problems.
167 | relationship = realpath_relation(loop_elt.get_path(),
168 | new_config_elt.get_path())
169 | if relationship == 'SAME_AS':
170 | if os.path.normpath(loop_elt.get_local_name()) != os.path.normpath(new_config_elt.get_local_name()):
171 | raise MultiProjectException("Elements with different local_name target the same path: %s, %s" % (loop_elt, new_config_elt))
172 | else:
173 | if (loop_elt == new_config_elt):
174 | return None
175 | if (merge_strategy == 'MergeReplace' or
176 | (merge_strategy == 'KillAppend' and
177 | index == len(self.trees) - 1)):
178 | self.trees[index] = new_config_elt
179 | # keep looping to check for overlap when replacing non-
180 | # scm with scm entry
181 | replaced = True
182 | if (loop_elt.is_vcs_element or not new_config_elt.is_vcs_element):
183 | return 'MergeReplace'
184 | elif merge_strategy == 'KillAppend':
185 | removals.append(loop_elt)
186 | elif merge_strategy == 'MergeKeep':
187 | return 'MergeKeep'
188 | else:
189 | raise LookupError(
190 | "No such merge strategy: %s" % str(merge_strategy))
191 | elif ((relationship == 'CHILD_OF' and new_config_elt.is_vcs_element())
192 | or (relationship == 'PARENT_OF' and loop_elt.is_vcs_element())):
193 | # we do not allow any elements to be children of scm elements
194 | # to allow for parallel updates and because wstool may
195 | # delete scm folders on update, and thus subfolders can be
196 | # deleted with their parents
197 | raise MultiProjectException(
198 | "Managed Element paths overlap: %s, %s" % (loop_elt,
199 | new_config_elt))
200 | if replaced:
201 | return 'MergeReplace'
202 | for loop_elt in removals:
203 | self.trees.remove(loop_elt)
204 | self.trees.append(new_config_elt)
205 | if len(removals) > 0:
206 | return 'KillAppend'
207 | return 'Append'
208 |
209 | def remove_element(self, local_name):
210 | """
211 | Removes element in the tree with the given local name (should be only one)
212 |
213 | :returns: True if such an element was found
214 | """
215 | removals = []
216 | for tree_el in self.trees:
217 | if tree_el.get_local_name() == local_name:
218 | removals.append(tree_el)
219 | if len(removals) > 0:
220 | for tree_el in removals:
221 | self.trees.remove(tree_el)
222 | return True
223 | return False
224 |
225 | def _create_vcs_config_element(self, scmtype, path, local_name, uri, version='', properties=None):
226 | try:
227 | eclass = self.registry[scmtype]
228 | except LookupError:
229 | raise MultiProjectException(
230 | "No VCS client registered for vcs type %s" % scmtype)
231 | return eclass(scmtype=scmtype,
232 | path=path,
233 | local_name=local_name,
234 | uri=uri,
235 | version=version,
236 | properties=properties)
237 |
238 | def get_base_path(self):
239 | return self.base_path
240 |
241 | def get_config_filename(self):
242 | return self.config_filename
243 |
244 | def get_source(self, versioned=False, vcs_only=False):
245 | """
246 | :param versioned: True returns sources as versioned PathSpec, False
247 | returns sources as simple PathSpec
248 | :param vcs_only: True returns only version-controlled sources, False
249 | returns all sources
250 | :returns: all elements that got added by user keystrokes
251 | (CLI and changed .rosinstall)
252 | """
253 | source_aggregate = []
254 | for tree_el in self.trees:
255 | if vcs_only and not tree_el.is_vcs_element():
256 | continue
257 |
258 | if not versioned or not tree_el.is_vcs_element():
259 | source_aggregate.append(tree_el.get_path_spec())
260 | else:
261 | source_aggregate.append(tree_el.get_versioned_path_spec())
262 | return source_aggregate
263 |
264 | def get_config_elements(self):
265 | source_aggregate = []
266 | for tree_el in self.trees:
267 | source_aggregate.append(tree_el)
268 | return source_aggregate
269 |
--------------------------------------------------------------------------------
/src/wstool/helpers.py:
--------------------------------------------------------------------------------
1 | # Software License Agreement (BSD License)
2 | #
3 | # Copyright (c) 2010, Willow Garage, Inc.
4 | # All rights reserved.
5 | #
6 | # Redistribution and use in source and binary forms, with or without
7 | # modification, are permitted provided that the following conditions
8 | # are met:
9 | #
10 | # * Redistributions of source code must retain the above copyright
11 | # notice, this list of conditions and the following disclaimer.
12 | # * Redistributions in binary form must reproduce the above
13 | # copyright notice, this list of conditions and the following
14 | # disclaimer in the documentation and/or other materials provided
15 | # with the distribution.
16 | # * Neither the name of Willow Garage, Inc. nor the names of its
17 | # contributors may be used to endorse or promote products derived
18 | # from this software without specific prior written permission.
19 | #
20 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 | # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 | # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 | # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 | # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 | # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 | # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 | # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 | # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 | # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 | # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 | # POSSIBILITY OF SUCH DAMAGE.
32 |
33 | import os
34 | import sys
35 | import codecs
36 | import subprocess
37 | from wstool.config_elements import SetupConfigElement
38 |
39 | ROSINSTALL_FILENAME = ".rosinstall"
40 |
41 | def get_ros_package_path(config):
42 | """ Return the simplifed ROS_PACKAGE_PATH """
43 | code_trees = []
44 | for tree_el in reversed(config.get_config_elements()):
45 | if not os.path.isfile(tree_el.get_path()):
46 | code_trees.append(tree_el.get_path())
47 | return code_trees
48 |
--------------------------------------------------------------------------------
/src/wstool/ui.py:
--------------------------------------------------------------------------------
1 | # Software License Agreement (BSD License)
2 | #
3 | # Copyright (c) 2009, Willow Garage, Inc.
4 | # All rights reserved.
5 | #
6 | # Redistribution and use in source and binary forms, with or without
7 | # modification, are permitted provided that the following conditions
8 | # are met:
9 | #
10 | # * Redistributions of source code must retain the above copyright
11 | # notice, this list of conditions and the following disclaimer.
12 | # * Redistributions in binary form must reproduce the above
13 | # copyright notice, this list of conditions and the following
14 | # disclaimer in the documentation and/or other materials provided
15 | # with the distribution.
16 | # * Neither the name of Willow Garage, Inc. nor the names of its
17 | # contributors may be used to endorse or promote products derived
18 | # from this software without specific prior written permission.
19 | #
20 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 | # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 | # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 | # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 | # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 | # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 | # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 | # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 | # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 | # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 | # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 | # POSSIBILITY OF SUCH DAMAGE.
32 |
33 | import sys
34 |
35 |
36 | class Ui(object):
37 | """
38 | wrap user interaction, such that client libraries may provide own
39 | implementation
40 | """
41 |
42 | # For now, primarily define this for replacement in unittests
43 | GLOBAL_UI = None
44 |
45 | @staticmethod
46 | def get_ui():
47 | if Ui.GLOBAL_UI is None:
48 | return Ui()
49 | return Ui.GLOBAL_UI
50 |
51 | @staticmethod
52 | def set_ui(uiarg):
53 | Ui.GLOBAL_UI = uiarg
54 |
55 | def __init__(self):
56 | pass
57 |
58 | def get_backup_path(self):
59 | """Interactive function asking the user to choose a path for backup"""
60 | backup_path = self.get_input("Please enter backup pathname: ")
61 | print(("backing up to %s" % backup_path))
62 | return backup_path
63 |
64 | def get_input(self, prompt):
65 | if sys.hexversion > 0x03000000:
66 | return input(prompt)
67 | else:
68 | return raw_input(prompt)
69 |
70 | def prompt_del_abort_retry(self,
71 | prompt,
72 | allow_skip=False,
73 | allow_inplace=False):
74 | """
75 | Interactive function asking the user to choose a conflict resolution
76 | :param prompt: message to display, str
77 | :param allow_skip: whether to display skip option, bool
78 | :param inplace: whether to show option for inplace replacing (symlinks)
79 | :return: user choice one of backup, delete, abort, inplace, skip
80 | """
81 | valid_modes = ['(d)elete and replace',
82 | '(a)bort']
83 | if allow_inplace:
84 | valid_modes.append('(i)nplace delete and replace at symlink')
85 | else:
86 | valid_modes.append('(b)ackup and replace')
87 | if allow_skip:
88 | valid_modes.append('(s)kip')
89 |
90 | mode = ""
91 | full_prompt = "%s\n %s: " % (prompt, ", ".join(valid_modes))
92 | while mode == "":
93 | mode_input = self.get_input(full_prompt)
94 | if not allow_inplace and mode_input == 'b':
95 | mode = 'backup'
96 | elif mode_input == 'd':
97 | mode = 'delete'
98 | elif mode_input == 'a':
99 | mode = 'abort'
100 | elif allow_inplace and mode_input == 'i':
101 | mode = 'inplace'
102 | elif allow_skip and mode_input == 's':
103 | mode = 'skip'
104 | return mode
105 |
--------------------------------------------------------------------------------
/src/wstool/wstool_cli.py:
--------------------------------------------------------------------------------
1 | # Software License Agreement (BSD License)
2 | #
3 | # Copyright (c) 2010, Willow Garage, Inc.
4 | # All rights reserved.
5 | #
6 | # Redistribution and use in source and binary forms, with or without
7 | # modification, are permitted provided that the following conditions
8 | # are met:
9 | #
10 | # * Redistributions of source code must retain the above copyright
11 | # notice, this list of conditions and the following disclaimer.
12 | # * Redistributions in binary form must reproduce the above
13 | # copyright notice, this list of conditions and the following
14 | # disclaimer in the documentation and/or other materials provided
15 | # with the distribution.
16 | # * Neither the name of Willow Garage, Inc. nor the names of its
17 | # contributors may be used to endorse or promote products derived
18 | # from this software without specific prior written permission.
19 | #
20 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 | # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 | # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 | # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 | # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 | # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 | # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 | # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 | # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 | # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 | # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 | # POSSIBILITY OF SUCH DAMAGE.
32 |
33 | """%(prog)s is a command to manipulate ROS workspaces. %(prog)s replaces its predecessor rosws.
34 |
35 | Official usage:
36 | %(prog)s CMD [ARGS] [OPTIONS]
37 |
38 | %(prog)s will try to infer install path from context
39 |
40 | Type '%(prog)s help' for usage.
41 | """
42 |
43 | from __future__ import print_function
44 | import os
45 | import sys
46 |
47 | from optparse import OptionParser
48 |
49 | from wstool.cli_common import get_info_table, get_workspace
50 | import wstool.multiproject_cmd as multiproject_cmd
51 | import wstool.__version__
52 |
53 | from wstool.helpers import ROSINSTALL_FILENAME
54 | from wstool.common import MultiProjectException
55 | from wstool.multiproject_cli import MultiprojectCLI, \
56 | __MULTIPRO_CMD_DICT__, __MULTIPRO_CMD_ALIASES__, \
57 | __MULTIPRO_CMD_HELP_LIST__, IndentedHelpFormatterWithNL, \
58 | list_usage, get_header
59 |
60 | ## This file adds or extends commands from multiproject_cli where ROS
61 | ## specific output has to be generated.
62 |
63 |
64 | _PROGNAME = 'wstool'
65 |
66 |
67 | class WstoolCLI(MultiprojectCLI):
68 |
69 | def __init__(self, config_filename=ROSINSTALL_FILENAME, progname=_PROGNAME):
70 |
71 | def config_generator(config, filename, header=None, spec=True,
72 | exact=False, vcs_only=False):
73 | wstool.multiproject_cmd.cmd_persist_config(
74 | config,
75 | filename,
76 | header,
77 | pretty=True,
78 | sort_with_localname=True,
79 | spec=spec,
80 | exact=exact,
81 | vcs_only=vcs_only)
82 |
83 | MultiprojectCLI.__init__(
84 | self,
85 | progname=progname,
86 | config_filename=config_filename,
87 | config_generator=config_generator)
88 |
89 |
90 | def wstool_main(argv=None, usage=None):
91 | """
92 | Calls the function corresponding to the first argument.
93 |
94 | :param argv: sys.argv by default
95 | :param usage: function printing usage string, multiproject_cli.list_usage by default
96 | """
97 | if argv is None:
98 | argv = sys.argv
99 | if (sys.argv[0] == '-c'):
100 | sys.argv = [_PROGNAME] + sys.argv[1:]
101 | if '--version' in argv:
102 | print("%s: \t%s\n%s" % (_PROGNAME,
103 | wstool.__version__.version,
104 | multiproject_cmd.cmd_version()))
105 | sys.exit(0)
106 |
107 | if not usage:
108 | usage = lambda: print(list_usage(progname=_PROGNAME,
109 | description=__doc__,
110 | command_keys=__MULTIPRO_CMD_HELP_LIST__,
111 | command_helps=__MULTIPRO_CMD_DICT__,
112 | command_aliases=__MULTIPRO_CMD_ALIASES__))
113 | workspace = None
114 | if len(argv) < 2:
115 | try:
116 | workspace = get_workspace(argv,
117 | os.getcwd(),
118 | config_filename=ROSINSTALL_FILENAME)
119 | argv.append('info')
120 | except MultiProjectException as e:
121 | print(str(e))
122 | usage()
123 | return 0
124 |
125 | if argv[1] in ['--help', '-h']:
126 | usage()
127 | return 0
128 |
129 | try:
130 | command = argv[1]
131 | args = argv[2:]
132 |
133 | if command == 'help':
134 | if len(argv) < 3:
135 | usage()
136 | return 0
137 |
138 | else:
139 | command = argv[2]
140 | args = argv[3:]
141 | args.insert(0, "--help")
142 | # help help
143 | if command == 'help':
144 | usage()
145 | return 0
146 | cli = WstoolCLI(progname=_PROGNAME)
147 |
148 | # commands for which we do not infer target workspace
149 | commands = {'init': cli.cmd_init}
150 | # commands which work on a workspace
151 | ws_commands = {
152 | 'info': cli.cmd_info,
153 | 'remove': cli.cmd_remove,
154 | 'set': cli.cmd_set,
155 | 'merge': cli.cmd_merge,
156 | 'export': cli.cmd_snapshot,
157 | 'diff': cli.cmd_diff,
158 | 'foreach': cli.cmd_foreach,
159 | 'scrape': cli.cmd_scrape,
160 | 'status': cli.cmd_status,
161 | 'update': cli.cmd_update}
162 | for label in list(ws_commands.keys()):
163 | if label in __MULTIPRO_CMD_ALIASES__:
164 | ws_commands[__MULTIPRO_CMD_ALIASES__[label]] = ws_commands[label]
165 |
166 | if command not in commands and command not in ws_commands:
167 | if os.path.exists(command):
168 | args = ['-t', command] + args
169 | command = 'info'
170 | else:
171 | if command.startswith('-'):
172 | print("First argument must be name of a command: %s" % command)
173 | else:
174 | print("Error: unknown command: %s" % command)
175 | usage()
176 | return 1
177 |
178 | if command in commands:
179 | return commands[command](args)
180 | else:
181 | if workspace is None and not '--help' in args and not '-h' in args:
182 | workspace = get_workspace(args,
183 | os.getcwd(),
184 | config_filename=ROSINSTALL_FILENAME)
185 | return ws_commands[command](workspace, args)
186 |
187 | except KeyboardInterrupt:
188 | return 1
189 |
--------------------------------------------------------------------------------
/stdeb.cfg:
--------------------------------------------------------------------------------
1 | [DEFAULT]
2 | Depends: subversion, mercurial, git-core, bzr, python-yaml, python-vcstools (>= 0.1.38)
3 | Depends3: subversion, mercurial, git-core, bzr, python3-yaml, python3-vcstools (>= 0.1.38)
4 | Conflicts: python3-wstool
5 | Conflicts3: python-wstool
6 | Suite: oneiric precise quantal raring saucy trusty utopic vivid wily xenial yakkety zesty artful bionic wheezy jessie stretch buster
7 | X-Python3-Version: >= 3.2
8 |
--------------------------------------------------------------------------------
/test/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vcstools/wstool/7f74a7997c7dee7c856516cbb4c59c15e2f72fee/test/__init__.py
--------------------------------------------------------------------------------
/test/example.yaml:
--------------------------------------------------------------------------------
1 | text: foobar
2 | number: 2
3 |
--------------------------------------------------------------------------------
/test/example_dirs/ros/stack.xml:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vcstools/wstool/7f74a7997c7dee7c856516cbb4c59c15e2f72fee/test/example_dirs/ros/stack.xml
--------------------------------------------------------------------------------
/test/example_dirs/ros_comm/stack.xml:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vcstools/wstool/7f74a7997c7dee7c856516cbb4c59c15e2f72fee/test/example_dirs/ros_comm/stack.xml
--------------------------------------------------------------------------------
/test/example_dirs/roscpp/manifest.xml:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vcstools/wstool/7f74a7997c7dee7c856516cbb4c59c15e2f72fee/test/example_dirs/roscpp/manifest.xml
--------------------------------------------------------------------------------
/test/io_wrapper.py:
--------------------------------------------------------------------------------
1 | class StringIO:
2 | """
3 | StringIO.StringIO does not exist in python3
4 | io.StringIO cannot cope with unicode
5 | """
6 |
7 | def __init__(self):
8 | self.stream = ''
9 |
10 | def write(self, data):
11 | self.stream += data
12 |
13 | def flush(self):
14 | pass
15 |
16 | def __getattr__(self, attr):
17 | return getattr(self.stream, attr)
18 |
19 | def getvalue(self):
20 | return self.stream
21 |
--------------------------------------------------------------------------------
/test/local/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vcstools/wstool/7f74a7997c7dee7c856516cbb4c59c15e2f72fee/test/local/__init__.py
--------------------------------------------------------------------------------
/test/local/mock_client.py:
--------------------------------------------------------------------------------
1 | # Software License Agreement (BSD License)
2 | #
3 | # Copyright (c) 2009, Willow Garage, Inc.
4 | # All rights reserved.
5 | #
6 | # Redistribution and use in source and binary forms, with or without
7 | # modification, are permitted provided that the following conditions
8 | # are met:
9 | #
10 | # * Redistributions of source code must retain the above copyright
11 | # notice, this list of conditions and the following disclaimer.
12 | # * Redistributions in binary form must reproduce the above
13 | # copyright notice, this list of conditions and the following
14 | # disclaimer in the documentation and/or other materials provided
15 | # with the distribution.
16 | # * Neither the name of Willow Garage, Inc. nor the names of its
17 | # contributors may be used to endorse or promote products derived
18 | # from this software without specific prior written permission.
19 | #
20 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 | # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 | # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 | # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 | # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 | # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 | # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 | # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 | # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 | # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 | # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 | # POSSIBILITY OF SUCH DAMAGE.
32 |
33 |
34 | class MockVcsClient():
35 | """
36 | Mocked vcs client. TODO: we should be using pathon magic mock instead.
37 | """
38 |
39 |
40 | class MockVcsClient():
41 |
42 | def __init__(self,
43 | scmtype='mocktype',
44 | path_exists=False,
45 | checkout_success=True,
46 | update_success=True,
47 | vcs_presence=False,
48 | url="mockurl",
49 | actualversion=None,
50 | specversion=None,
51 | remoteversion=None):
52 | self.scmtype = scmtype
53 | self.path_exists_flag = path_exists
54 | self.checkout_success = checkout_success
55 | self.update_success = update_success
56 | self.vcs_presence = vcs_presence
57 | self.mockurl = url
58 | self.checkedout = vcs_presence
59 | self.updated = False
60 | self.actualversion = actualversion
61 | self.specversion = specversion
62 | self.remoteversion = remoteversion
63 |
64 | def get_vcs_type_name(self):
65 | return self.scmtype
66 |
67 | def get_diff(self, basepath=None):
68 | return self.scmtype + "mockdiff%s" % basepath
69 |
70 | def get_version(self, revision=None):
71 | if revision == None:
72 | return self.actualversion
73 | else:
74 | return self.specversion
75 |
76 | def get_remote_version(self, fetch=False):
77 | return self.remoteversion
78 |
79 | def get_current_version_label(self):
80 | return self.scmtype + "mockcurrentversionlabel"
81 |
82 | def get_status(self, basepath=None, untracked=False):
83 | return self.scmtype + " mockstatus%s,%s" % (basepath, untracked)
84 |
85 | def path_exists(self):
86 | return self.path_exists_flag
87 |
88 | def checkout(self, uri=None, version=None, verbose=False, timeout=None, shallow=False):
89 | self.checkedout = True
90 | return self.checkout_success
91 |
92 | def update(self, version, verbose=False, timeout=None):
93 | self.updated = True
94 | return self.update_success
95 |
96 | def detect_presence(self):
97 | return self.vcs_presence
98 |
99 | def get_url(self):
100 | return self.mockurl
101 |
102 | def url_matches(self, url, url_or_shortcut):
103 | return (url == url_or_shortcut or
104 | url_or_shortcut is None or
105 | url_or_shortcut.endswith('_shortcut'))
106 |
--------------------------------------------------------------------------------
/test/local/test_config_elt.py:
--------------------------------------------------------------------------------
1 | # Software License Agreement (BSD License)
2 | #
3 | # Copyright (c) 2009, Willow Garage, Inc.
4 | # All rights reserved.
5 | #
6 | # Redistribution and use in source and binary forms, with or without
7 | # modification, are permitted provided that the following conditions
8 | # are met:
9 | #
10 | # * Redistributions of source code must retain the above copyright
11 | # notice, this list of conditions and the following disclaimer.
12 | # * Redistributions in binary form must reproduce the above
13 | # copyright notice, this list of conditions and the following
14 | # disclaimer in the documentation and/or other materials provided
15 | # with the distribution.
16 | # * Neither the name of Willow Garage, Inc. nor the names of its
17 | # contributors may be used to endorse or promote products derived
18 | # from this software without specific prior written permission.
19 | #
20 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 | # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 | # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 | # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 | # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 | # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 | # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 | # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 | # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 | # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 | # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 | # POSSIBILITY OF SUCH DAMAGE.
32 |
33 | import unittest
34 |
35 | import wstool.config
36 | from wstool.common import MultiProjectException
37 | from . import mock_client
38 |
39 |
40 | class ConfigElements_Test(unittest.TestCase):
41 |
42 | def test_simple_config_element_API(self):
43 | path = "some/path"
44 | localname = "some/local/name"
45 | other1 = wstool.config_elements.ConfigElement(path, localname)
46 | self.assertEqual(path, other1.get_path())
47 | self.assertEqual(localname, other1.get_local_name())
48 | self.assertFalse(other1.is_vcs_element())
49 | other1 = wstool.config_elements.OtherConfigElement(path, localname)
50 | self.assertEqual(path, other1.get_path())
51 | self.assertEqual(localname, other1.get_local_name())
52 | self.assertEqual({'other': {'local-name': 'some/local/name'}}, other1.get_path_spec().get_legacy_yaml())
53 | self.assertFalse(other1.is_vcs_element())
54 | other1 = wstool.config_elements.SetupConfigElement(path, localname)
55 | self.assertEqual(path, other1.get_path())
56 | self.assertEqual(localname, other1.get_local_name())
57 | self.assertEqual({'setup-file': {'local-name': 'some/local/name'}}, other1.get_path_spec().get_legacy_yaml())
58 | self.assertFalse(other1.is_vcs_element())
59 | other1 = wstool.config_elements.OtherConfigElement(path, localname, properties=[{}])
60 | self.assertEqual(path, other1.get_path())
61 | self.assertEqual(localname, other1.get_local_name())
62 | self.assertEqual({'other': {'local-name': 'some/local/name'}}, other1.get_path_spec().get_legacy_yaml())
63 | self.assertFalse(other1.is_vcs_element())
64 | other1 = wstool.config_elements.OtherConfigElement(path, localname, properties=['meta'])
65 | self.assertEqual(path, other1.get_path())
66 | self.assertEqual(localname, other1.get_local_name())
67 | self.assertEqual({'other': {'local-name': 'some/local/name', 'meta': None}}, other1.get_path_spec().get_legacy_yaml())
68 | self.assertFalse(other1.is_vcs_element())
69 | other1 = wstool.config_elements.OtherConfigElement(path, localname, properties=[{'meta': {'repo-name': 'skynetish-ros-pkg'}}])
70 | self.assertEqual(path, other1.get_path())
71 | self.assertEqual(localname, other1.get_local_name())
72 | self.assertEqual({'other': {'local-name': 'some/local/name', 'meta': {'repo-name': 'skynetish-ros-pkg'}}}, other1.get_path_spec().get_legacy_yaml())
73 | self.assertFalse(other1.is_vcs_element())
74 |
75 | def test_mock_vcs_config_element_init(self):
76 | path = "some/path"
77 | localname = "some/local/name"
78 | try:
79 | wstool.config_elements.AVCSConfigElement("mock", None, None, None)
80 | self.fail("Exception expected")
81 | except MultiProjectException:
82 | pass
83 | try:
84 | wstool.config_elements.AVCSConfigElement("mock", "path", None, None)
85 | self.fail("Exception expected")
86 | except MultiProjectException:
87 | pass
88 | try:
89 | wstool.config_elements.AVCSConfigElement("mock", None, None, "some/uri")
90 | self.fail("Exception expected")
91 | except MultiProjectException:
92 | pass
93 | path = "some/path"
94 | localname = "some/local/name"
95 | uri = 'some/uri'
96 | version = 'some.version'
97 | vcsc = wstool.config_elements.AVCSConfigElement("mock", path, localname, uri, vcsc=mock_client.MockVcsClient())
98 | self.assertEqual(path, vcsc.get_path())
99 | self.assertEqual(localname, vcsc.get_local_name())
100 | self.assertEqual(uri, vcsc.uri)
101 | self.assertTrue(vcsc.is_vcs_element())
102 | self.assertEqual("mocktypemockdiffNone", vcsc.get_diff())
103 | self.assertEqual("mocktype mockstatusNone,False", vcsc.get_status())
104 | self.assertEqual({'mock': {'local-name': 'some/local/name', 'uri': 'some/uri'}}, vcsc.get_path_spec().get_legacy_yaml())
105 | self.assertEqual({'mock': {'local-name': 'some/local/name', 'uri': 'some/uri', }}, vcsc.get_versioned_path_spec().get_legacy_yaml())
106 |
107 | vcsc = wstool.config_elements.AVCSConfigElement("mock", path, localname, uri, None, vcsc=mock_client.MockVcsClient())
108 | self.assertEqual(path, vcsc.get_path())
109 | self.assertEqual(localname, vcsc.get_local_name())
110 | self.assertEqual(uri, vcsc.uri)
111 | self.assertTrue(vcsc.is_vcs_element())
112 | self.assertEqual("mocktypemockdiffNone", vcsc.get_diff())
113 | self.assertEqual("mocktype mockstatusNone,False", vcsc.get_status())
114 | self.assertEqual({'mock': {'local-name': 'some/local/name', 'uri': 'some/uri'}}, vcsc.get_path_spec().get_legacy_yaml())
115 | self.assertEqual({'mock': {'local-name': 'some/local/name', 'uri': 'some/uri', }}, vcsc.get_versioned_path_spec().get_legacy_yaml())
116 |
117 | vcsc = wstool.config_elements.AVCSConfigElement("mock", path, localname, uri, version, vcsc=mock_client.MockVcsClient())
118 | self.assertEqual(path, vcsc.get_path())
119 | self.assertEqual(localname, vcsc.get_local_name())
120 | self.assertEqual(uri, vcsc.uri)
121 | self.assertTrue(vcsc.is_vcs_element())
122 | self.assertEqual("mocktypemockdiffNone", vcsc.get_diff())
123 | self.assertEqual("mocktype mockstatusNone,False", vcsc.get_status())
124 | self.assertEqual({'mock': {'local-name': 'some/local/name', 'version': 'some.version', 'uri': 'some/uri'}}, vcsc.get_path_spec().get_legacy_yaml())
125 | self.assertEqual({'mock': {'local-name': 'some/local/name', 'version': 'some.version', 'uri': 'some/uri'}}, vcsc.get_versioned_path_spec().get_legacy_yaml())
126 |
127 | vcsc = wstool.config_elements.AVCSConfigElement(
128 | "mock", path, localname, uri, version,
129 | vcsc=mock_client.MockVcsClient(),
130 | properties=[{'meta': {'repo-name': 'skynetish-ros-pkg'}}])
131 | self.assertEqual(path, vcsc.get_path())
132 | self.assertEqual(localname, vcsc.get_local_name())
133 | self.assertEqual(uri, vcsc.uri)
134 | self.assertTrue(vcsc.is_vcs_element())
135 | self.assertEqual("mocktypemockdiffNone", vcsc.get_diff())
136 | self.assertEqual("mocktype mockstatusNone,False", vcsc.get_status())
137 | self.assertEqual({'mock': {'local-name': 'some/local/name', 'version': 'some.version', 'uri': 'some/uri', 'meta': {'repo-name': 'skynetish-ros-pkg'}}}, vcsc.get_path_spec().get_legacy_yaml())
138 | self.assertEqual({'mock': {'local-name': 'some/local/name', 'version': 'some.version', 'uri': 'some/uri', 'meta': {'repo-name': 'skynetish-ros-pkg'}}}, vcsc.get_versioned_path_spec().get_legacy_yaml())
139 |
140 | # this time using 'uri_shortcut' in mock_client.MockVcsClient, get special treatment un url_matches()
141 | uri2 = 'some/uri2'
142 | vcsc = wstool.config_elements.AVCSConfigElement(
143 | "mock", path, localname, uri2, version,
144 | vcsc=mock_client.MockVcsClient(url='url_shortcut'),
145 | properties=[{'meta': {'repo-name': 'skynetish-ros-pkg'}}])
146 | self.assertEqual(path, vcsc.get_path())
147 | self.assertEqual(localname, vcsc.get_local_name())
148 | self.assertEqual(uri2, vcsc.uri)
149 | self.assertTrue(vcsc.is_vcs_element())
150 | self.assertEqual("mocktypemockdiffNone", vcsc.get_diff())
151 | self.assertEqual("mocktype mockstatusNone,False", vcsc.get_status())
152 | self.assertEqual({'mock': {'local-name': 'some/local/name', 'version': 'some.version', 'uri': 'some/uri2', 'meta': {'repo-name': 'skynetish-ros-pkg'}}}, vcsc.get_path_spec().get_legacy_yaml())
153 | self.assertEqual({'mock': {'local-name': 'some/local/name', 'version': 'some.version', 'uri': 'some/uri2', 'meta': {'repo-name': 'skynetish-ros-pkg'}}}, vcsc.get_versioned_path_spec().get_legacy_yaml())
154 |
155 | def test_mock_install(self):
156 | path = "some/path"
157 | localname = "some/local/name"
158 | uri = 'some/uri'
159 | version = 'some.version'
160 | mockclient = mock_client.MockVcsClient(url=uri)
161 | vcsc = wstool.config_elements.AVCSConfigElement("mock", path, localname, uri, None, vcsc=mockclient)
162 | vcsc.install()
163 | self.assertTrue(mockclient.checkedout)
164 | self.assertFalse(mockclient.updated)
165 | # checkout failure
166 | mockclient = mock_client.MockVcsClient(url=uri, checkout_success=False)
167 | try:
168 | vcsc = wstool.config_elements.AVCSConfigElement("mock", path, localname, uri, None, vcsc=mockclient)
169 | vcsc.install()
170 | self.fail("should have raised Exception")
171 | except MultiProjectException:
172 | pass
173 |
--------------------------------------------------------------------------------
/test/local/test_diff_functions_bzr.py:
--------------------------------------------------------------------------------
1 | # Software License Agreement (BSD License)
2 | #
3 | # Copyright (c) 2009, Willow Garage, Inc.
4 | # All rights reserved.
5 | #
6 | # Redistribution and use in source and binary forms, with or without
7 | # modification, are permitted provided that the following conditions
8 | # are met:
9 | #
10 | # * Redistributions of source code must retain the above copyright
11 | # notice, this list of conditions and the following disclaimer.
12 | # * Redistributions in binary form must reproduce the above
13 | # copyright notice, this list of conditions and the following
14 | # disclaimer in the documentation and/or other materials provided
15 | # with the distribution.
16 | # * Neither the name of Willow Garage, Inc. nor the names of its
17 | # contributors may be used to endorse or promote products derived
18 | # from this software without specific prior written permission.
19 | #
20 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 | # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 | # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 | # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 | # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 | # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 | # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 | # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 | # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 | # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 | # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 | # POSSIBILITY OF SUCH DAMAGE.
32 |
33 | from __future__ import unicode_literals
34 |
35 | import os
36 | import sys
37 | from test.io_wrapper import StringIO
38 | import subprocess
39 |
40 | import wstool
41 | import wstool.helpers
42 | import wstool.wstool_cli
43 | from wstool.wstool_cli import WstoolCLI
44 | from wstool.wstool_cli import wstool_main
45 |
46 | import test.scm_test_base
47 | from test.scm_test_base import AbstractSCMTest, _add_to_file, _nth_line_split
48 |
49 |
50 | def create_bzr_repo(remote_path):
51 | # create a "remote" repo
52 | subprocess.check_call(["bzr", "init"], cwd=remote_path)
53 | subprocess.check_call(["touch", "fixed.txt"], cwd=remote_path)
54 | subprocess.check_call(["touch", "modified.txt"], cwd=remote_path)
55 | subprocess.check_call(["touch", "modified-fs.txt"], cwd=remote_path)
56 | subprocess.check_call(["touch", "deleted.txt"], cwd=remote_path)
57 | subprocess.check_call(["touch", "deleted-fs.txt"], cwd=remote_path)
58 | subprocess.check_call(["bzr", "add", "fixed.txt"], cwd=remote_path)
59 | subprocess.check_call(["bzr", "add", "modified.txt"], cwd=remote_path)
60 | subprocess.check_call(["bzr", "add", "modified-fs.txt"], cwd=remote_path)
61 | subprocess.check_call(["bzr", "add", "deleted.txt"], cwd=remote_path)
62 | subprocess.check_call(["bzr", "add", "deleted-fs.txt"], cwd=remote_path)
63 | subprocess.check_call(["bzr", "commit", "-m", "modified"], cwd=remote_path)
64 |
65 |
66 | def modify_bzr_repo(clone_path):
67 | # make local modifications
68 | subprocess.check_call(["rm", "deleted-fs.txt"], cwd=clone_path)
69 | subprocess.check_call(["bzr", "rm", "deleted.txt"], cwd=clone_path)
70 | _add_to_file(os.path.join(clone_path, "modified-fs.txt"), "foo\n")
71 | _add_to_file(os.path.join(clone_path, "modified.txt"), "foo\n")
72 | _add_to_file(os.path.join(clone_path, "added-fs.txt"), "tada\n")
73 | _add_to_file(os.path.join(clone_path, "added.txt"), "flam\n")
74 | subprocess.check_call(["bzr", "add", "added.txt"], cwd=clone_path)
75 |
76 |
77 | class WstoolDiffBzrTest(AbstractSCMTest):
78 |
79 | @classmethod
80 | def setUpClass(self):
81 | AbstractSCMTest.setUpClass()
82 | remote_path = os.path.join(self.test_root_path, "remote")
83 | os.makedirs(remote_path)
84 |
85 | create_bzr_repo(remote_path)
86 |
87 | # wstool the remote repo and fake ros
88 | _add_to_file(os.path.join(self.local_path, ".rosinstall"),
89 | "- other: {local-name: ../ros}\n- bzr: {local-name: clone, uri: %s}" % remote_path)
90 | cmd = ["wstool", "update", "-t", "ws"]
91 | os.chdir(self.test_root_path)
92 | wstool_main(cmd)
93 |
94 | clone_path = os.path.join(self.local_path, "clone")
95 |
96 | modify_bzr_repo(clone_path)
97 |
98 | def check_diff_output(self, output):
99 | # uncomment following line for easiest way to get actual output with escapes
100 | # self.assertEqual(None, output);
101 |
102 | # bzr writes date-time of file into diff
103 | self.assertTrue(output.startswith("=== added file 'added.txt'\n--- clone/added.txt"), msg=0)
104 | self.assertTrue(0 < output.find("+++ clone/added.txt"), msg=1)
105 | self.assertTrue(0 < output.find("@@ -0,0 +1,1 @@\n+flam\n\n"), msg=2)
106 | self.assertTrue(0 < output.find("=== removed file 'deleted-fs.txt'\n=== removed file 'deleted.txt'\n=== modified file 'modified-fs.txt'\n--- clone/modified-fs.txt"), msg=3)
107 | self.assertTrue(0 < output.find("@@ -0,0 +1,1 @@\n+foo\n\n=== modified file 'modified.txt'\n--- clone/modified.txt"), msg=4)
108 |
109 | def test_wstool_diff_bzr_outside(self):
110 | """Test diff output for bzr when run outside workspace"""
111 | cmd = ["wstool", "diff", "-t", "ws"]
112 | os.chdir(self.test_root_path)
113 | sys.stdout = output = StringIO()
114 | wstool_main(cmd)
115 | sys.stdout = sys.__stdout__
116 | output = output.getvalue()
117 | self.check_diff_output(output)
118 |
119 | cli = WstoolCLI()
120 | self.assertEqual(0, cli.cmd_diff(os.path.join(self.test_root_path, 'ws'), []))
121 |
122 |
123 | def test_wstool_diff_bzr_inside(self):
124 | """Test diff output for bzr when run inside workspace"""
125 | directory = self.test_root_path + "/ws"
126 |
127 | cmd = ["wstool", "diff"]
128 | os.chdir(directory)
129 | sys.stdout = output = StringIO()
130 | wstool_main(cmd)
131 | output = output.getvalue()
132 | sys.stdout = sys.__stdout__
133 | self.check_diff_output(output)
134 |
135 | cli = WstoolCLI()
136 | self.assertEqual(0, cli.cmd_diff(directory, []))
137 |
138 | def test_wstool_status_bzr_inside(self):
139 | """Test status output for bzr when run inside workspace"""
140 | directory = self.test_root_path + "/ws"
141 |
142 | cmd = ["wstool", "status"]
143 | os.chdir(directory)
144 | sys.stdout = output = StringIO()
145 | wstool_main(cmd)
146 | output = output.getvalue()
147 | sys.stdout = sys.__stdout__
148 | self.assertEqual('+N clone/added.txt\n D clone/deleted-fs.txt\n-D clone/deleted.txt\n M clone/modified-fs.txt\n M clone/modified.txt\n', output)
149 |
150 | cli = WstoolCLI()
151 | self.assertEqual(0, cli.cmd_status(directory, []))
152 |
153 | def test_wstool_status_bzr_outside(self):
154 | """Test status output for bzr when run outside workspace"""
155 |
156 | cmd = ["wstool", "status", "-t", "ws"]
157 | os.chdir(self.test_root_path)
158 | sys.stdout = output = StringIO()
159 | wstool_main(cmd)
160 | sys.stdout = sys.__stdout__
161 | output = output.getvalue()
162 | self.assertEqual('+N clone/added.txt\n D clone/deleted-fs.txt\n-D clone/deleted.txt\n M clone/modified-fs.txt\n M clone/modified.txt\n', output)
163 |
164 | cli = WstoolCLI()
165 | self.assertEqual(0, cli.cmd_status(os.path.join(self.test_root_path, 'ws'), []))
166 |
167 | def test_wstool_status_bzr_untracked(self):
168 | """Test status output for bzr when run outside workspace"""
169 |
170 | cmd = ["wstool", "status", "-t", "ws", "--untracked"]
171 | os.chdir(self.test_root_path)
172 | sys.stdout = output = StringIO()
173 | wstool_main(cmd)
174 | sys.stdout = sys.__stdout__
175 | output = output.getvalue()
176 | self.assertEqual('? clone/added-fs.txt\n+N clone/added.txt\n D clone/deleted-fs.txt\n-D clone/deleted.txt\n M clone/modified-fs.txt\n M clone/modified.txt\n', output)
177 |
178 | cli = WstoolCLI()
179 | self.assertEqual(0, cli.cmd_status(os.path.join(self.test_root_path, 'ws'), ["--untracked"]))
180 |
181 | def test_wstool_info_bzr(self):
182 | cmd = ["wstool", "info", "-t", "ws"]
183 | os.chdir(self.test_root_path)
184 | sys.stdout = output = StringIO()
185 | wstool_main(cmd)
186 | output = output.getvalue()
187 | tokens = _nth_line_split(-2, output)
188 | self.assertEqual(['clone', 'M', 'bzr'], tokens[0:3], output)
189 |
190 | cli = WstoolCLI()
191 | self.assertEqual(0, cli.cmd_info(os.path.join(self.test_root_path, 'ws'), []))
192 |
193 |
194 | class WstoolInfoBzrTest(AbstractSCMTest):
195 |
196 | def setUp(self):
197 | AbstractSCMTest.setUp(self)
198 | remote_path = os.path.join(self.test_root_path, "remote")
199 | os.makedirs(remote_path)
200 |
201 | # create a "remote" repo
202 | subprocess.check_call(["bzr", "init"], cwd=remote_path)
203 | subprocess.check_call(["touch", "test.txt"], cwd=remote_path)
204 | subprocess.check_call(["bzr", "add", "test.txt"], cwd=remote_path)
205 | subprocess.check_call(["bzr", "commit", "-m", "modified"], cwd=remote_path)
206 | self.version_init = "1"
207 | subprocess.check_call(["bzr", "tag", "footag"], cwd=remote_path)
208 | subprocess.check_call(["touch", "test2.txt"], cwd=remote_path)
209 | subprocess.check_call(["bzr", "add", "test2.txt"], cwd=remote_path)
210 | subprocess.check_call(["bzr", "commit", "-m", "modified"], cwd=remote_path)
211 | self.version_end = "2"
212 |
213 | # wstool the remote repo and fake ros
214 | _add_to_file(os.path.join(self.local_path, ".rosinstall"), "- other: {local-name: ../ros}\n- bzr: {local-name: clone, uri: ../remote}")
215 |
216 | cmd = ["wstool", "update"]
217 | os.chdir(self.local_path)
218 | sys.stdout = output = StringIO()
219 | wstool_main(cmd)
220 | output = output.getvalue()
221 | sys.stdout = sys.__stdout__
222 |
223 | def test_rosinstall_detailed_locapath_info(self):
224 | cmd = ["wstool", "info", "-t", "ws"]
225 | os.chdir(self.test_root_path)
226 | sys.stdout = output = StringIO()
227 | wstool_main(cmd)
228 | output = output.getvalue()
229 |
230 | tokens = _nth_line_split(-2, output)
231 | self.assertEqual(['clone', 'bzr', self.version_end, os.path.join(self.test_root_path, 'remote')], tokens)
232 |
233 | clone_path = os.path.join(self.local_path, "clone")
234 | # make local modifications check
235 | subprocess.check_call(["rm", "test2.txt"], cwd=clone_path)
236 | sys.stdout = output = StringIO()
237 | wstool_main(cmd)
238 | output = output.getvalue()
239 | tokens = _nth_line_split(-2, output)
240 | self.assertEqual(['clone', 'M', 'bzr', self.version_end, os.path.join(self.test_root_path, 'remote')], tokens)
241 |
242 | subprocess.check_call(["rm", ".rosinstall"], cwd=self.local_path)
243 | _add_to_file(os.path.join(self.local_path, ".rosinstall"), "- other: {local-name: ../ros}\n- bzr: {local-name: clone, uri: ../remote, version: \"footag\"}")
244 | os.chdir(self.test_root_path)
245 | sys.stdout = output = StringIO()
246 | wstool_main(cmd)
247 | output = output.getvalue()
248 | tokens = _nth_line_split(-2, output)
249 | self.assertEqual(['clone', 'MV', 'bzr', 'footag', self.version_end, "(%s)" % self.version_init, os.path.join(self.test_root_path, 'remote')], tokens)
250 |
251 | subprocess.check_call(["rm", "-rf", "clone"], cwd=self.local_path)
252 | os.chdir(self.test_root_path)
253 | sys.stdout = output = StringIO()
254 | wstool_main(cmd)
255 | output = output.getvalue()
256 | tokens = _nth_line_split(-2, output)
257 | self.assertEqual(['clone', 'x', 'bzr', 'footag', os.path.join(self.test_root_path, 'remote')], tokens)
258 |
--------------------------------------------------------------------------------
/test/local/test_diff_functions_hg.py:
--------------------------------------------------------------------------------
1 | # Software License Agreement (BSD License)
2 | #
3 | # Copyright (c) 2009, Willow Garage, Inc.
4 | # All rights reserved.
5 | #
6 | # Redistribution and use in source and binary forms, with or without
7 | # modification, are permitted provided that the following conditions
8 | # are met:
9 | #
10 | # * Redistributions of source code must retain the above copyright
11 | # notice, this list of conditions and the following disclaimer.
12 | # * Redistributions in binary form must reproduce the above
13 | # copyright notice, this list of conditions and the following
14 | # disclaimer in the documentation and/or other materials provided
15 | # with the distribution.
16 | # * Neither the name of Willow Garage, Inc. nor the names of its
17 | # contributors may be used to endorse or promote products derived
18 | # from this software without specific prior written permission.
19 | #
20 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 | # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 | # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 | # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 | # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 | # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 | # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 | # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 | # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 | # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 | # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 | # POSSIBILITY OF SUCH DAMAGE.
32 |
33 | from __future__ import unicode_literals
34 |
35 | import os
36 | import sys
37 | from test.io_wrapper import StringIO
38 | import subprocess
39 |
40 | import wstool
41 | import wstool.helpers
42 | import wstool.wstool_cli
43 | from wstool.wstool_cli import WstoolCLI
44 | from wstool.wstool_cli import wstool_main
45 |
46 | import test.scm_test_base
47 | from test.scm_test_base import AbstractSCMTest, _add_to_file, _nth_line_split
48 |
49 |
50 | def create_hg_repo(remote_path):
51 | # create a "remote" repo
52 | subprocess.check_call(["hg", "init"], cwd=remote_path)
53 | subprocess.check_call(["touch", "fixed.txt"], cwd=remote_path)
54 | subprocess.check_call(["touch", "modified.txt"], cwd=remote_path)
55 | subprocess.check_call(["touch", "modified-fs.txt"], cwd=remote_path)
56 | subprocess.check_call(["touch", "deleted.txt"], cwd=remote_path)
57 | subprocess.check_call(["touch", "deleted-fs.txt"], cwd=remote_path)
58 | subprocess.check_call(["hg", "add", "fixed.txt"], cwd=remote_path)
59 | subprocess.check_call(["hg", "add", "modified.txt"], cwd=remote_path)
60 | subprocess.check_call(["hg", "add", "modified-fs.txt"], cwd=remote_path)
61 | subprocess.check_call(["hg", "add", "deleted.txt"], cwd=remote_path)
62 | subprocess.check_call(["hg", "add", "deleted-fs.txt"], cwd=remote_path)
63 | subprocess.check_call(["hg", "commit", "-m", "modified"], cwd=remote_path)
64 |
65 |
66 | def modify_hg_repo(clone_path):
67 | # make local modifications
68 | subprocess.check_call(["rm", "deleted-fs.txt"], cwd=clone_path)
69 | subprocess.check_call(["hg", "rm", "deleted.txt"], cwd=clone_path)
70 | _add_to_file(os.path.join(clone_path, "modified-fs.txt"), "foo\n")
71 | _add_to_file(os.path.join(clone_path, "modified.txt"), "foo\n")
72 | _add_to_file(os.path.join(clone_path, "added-fs.txt"), "tada\n")
73 | _add_to_file(os.path.join(clone_path, "added.txt"), "flam\n")
74 | subprocess.check_call(["hg", "add", "added.txt"], cwd=clone_path)
75 |
76 |
77 | class WstoolDiffHgTest(AbstractSCMTest):
78 |
79 | @classmethod
80 | def setUpClass(self):
81 | AbstractSCMTest.setUpClass()
82 | remote_path = os.path.join(self.test_root_path, "remote")
83 | os.makedirs(remote_path)
84 |
85 | create_hg_repo(remote_path)
86 |
87 | # wstool the remote repo and fake ros
88 | _add_to_file(os.path.join(self.local_path, ".rosinstall"), "- other: {local-name: ../ros}\n- hg: {local-name: clone, uri: ../remote}")
89 |
90 | cmd = ["wstool", "update", "-t", "ws"]
91 | os.chdir(self.test_root_path)
92 | wstool_main(cmd)
93 |
94 | clone_path = os.path.join(self.local_path, "clone")
95 |
96 | modify_hg_repo(clone_path)
97 |
98 | def check_diff_output(self, output):
99 | # sha ids are always same with hg
100 | self.assertEqual('diff --git clone/added.txt clone/added.txt\nnew file mode 100644\n--- /dev/null\n+++ clone/added.txt\n@@ -0,0 +1,1 @@\n+flam\ndiff --git clone/deleted.txt clone/deleted.txt\ndeleted file mode 100644\ndiff --git clone/modified-fs.txt clone/modified-fs.txt\n--- clone/modified-fs.txt\n+++ clone/modified-fs.txt\n@@ -0,0 +1,1 @@\n+foo\ndiff --git clone/modified.txt clone/modified.txt\n--- clone/modified.txt\n+++ clone/modified.txt\n@@ -0,0 +1,1 @@\n+foo\n', output)
101 |
102 | def test_wstool_diff_hg_outside(self):
103 | """Test diff output for hg when run outside workspace"""
104 |
105 | cmd = ["wstool", "diff", "-t", "ws"]
106 | os.chdir(self.test_root_path)
107 | sys.stdout = output = StringIO()
108 | wstool_main(cmd)
109 | sys.stdout = sys.__stdout__
110 | output = output.getvalue()
111 | self.check_diff_output(output)
112 |
113 | cli = WstoolCLI()
114 | self.assertEqual(0, cli.cmd_diff(os.path.join(self.test_root_path, 'ws'), []))
115 |
116 | def test_wstool_diff_hg_inside(self):
117 | """Test diff output for hg when run inside workspace"""
118 | directory = self.test_root_path + "/ws"
119 |
120 | cmd = ["wstool", "diff"]
121 | os.chdir(directory)
122 | sys.stdout = output = StringIO()
123 | wstool_main(cmd)
124 | output = output.getvalue()
125 | sys.stdout = sys.__stdout__
126 | self.check_diff_output(output)
127 |
128 | cli = WstoolCLI()
129 | self.assertEqual(0, cli.cmd_status(directory, []))
130 |
131 | def test_wstool_status_hg_inside(self):
132 | """Test status output for hg when run inside workspace"""
133 | directory = self.test_root_path + "/ws"
134 |
135 | cmd = ["wstool", "status"]
136 | os.chdir(directory)
137 | sys.stdout = output = StringIO()
138 | wstool_main(cmd)
139 | output = output.getvalue()
140 | sys.stdout = sys.__stdout__
141 | self.assertEqual('M clone/modified-fs.txt\nM clone/modified.txt\nA clone/added.txt\nR clone/deleted.txt\n! clone/deleted-fs.txt\n', output)
142 |
143 | cli = WstoolCLI()
144 | self.assertEqual(0, cli.cmd_diff(directory, []))
145 |
146 | def test_wstool_status_hg_outside(self):
147 | """Test status output for hg when run outside workspace"""
148 |
149 | cmd = ["wstool", "status", "-t", "ws"]
150 | os.chdir(self.test_root_path)
151 | sys.stdout = output = StringIO()
152 | wstool_main(cmd)
153 | sys.stdout = sys.__stdout__
154 | output = output.getvalue()
155 | self.assertEqual('M clone/modified-fs.txt\nM clone/modified.txt\nA clone/added.txt\nR clone/deleted.txt\n! clone/deleted-fs.txt\n', output)
156 |
157 | cli = WstoolCLI()
158 | self.assertEqual(0, cli.cmd_status(os.path.join(self.test_root_path, 'ws'), []))
159 |
160 | def test_wstool_status_hg_untracked(self):
161 | """Test untracked status output for hg when run outside workspace"""
162 | cmd = ["wstool", "status", "-t", "ws", "--untracked"]
163 | os.chdir(self.test_root_path)
164 | sys.stdout = output = StringIO()
165 | wstool_main(cmd)
166 | sys.stdout = sys.__stdout__
167 | output = output.getvalue()
168 | self.assertEqual('M clone/modified-fs.txt\nM clone/modified.txt\nA clone/added.txt\nR clone/deleted.txt\n! clone/deleted-fs.txt\n? clone/added-fs.txt\n', output)
169 |
170 | cli = WstoolCLI()
171 | self.assertEqual(0, cli.cmd_status(os.path.join(self.test_root_path, 'ws'), ["--untracked"]))
172 |
173 | def test_wstool_info_hg(self):
174 | cmd = ["wstool", "info", "-t", "ws"]
175 | os.chdir(self.test_root_path)
176 | sys.stdout = output = StringIO()
177 | wstool_main(cmd)
178 | output = output.getvalue()
179 | tokens = _nth_line_split(-2, output)
180 | self.assertEqual(['clone', 'M', 'hg'], tokens[0:3], output)
181 |
182 | cli = WstoolCLI()
183 | self.assertEqual(0, cli.cmd_info(os.path.join(self.test_root_path, 'ws'), []))
184 |
185 |
186 | class WstoolInfoHgTest(AbstractSCMTest):
187 |
188 | def setUp(self):
189 | AbstractSCMTest.setUp(self)
190 | remote_path = os.path.join(self.test_root_path, "remote")
191 | os.makedirs(remote_path)
192 |
193 | # create a "remote" repo
194 | subprocess.check_call(["hg", "init"], cwd=remote_path)
195 | subprocess.check_call(["touch", "test.txt"], cwd=remote_path)
196 | subprocess.check_call(["hg", "add", "test.txt"], cwd=remote_path)
197 | subprocess.check_call(["hg", "commit", "-m", "modified"], cwd=remote_path)
198 | po = subprocess.Popen(["hg", "log", "--template", "'{node|short}'", "-l1"], cwd=remote_path, stdout=subprocess.PIPE)
199 | self.version_init = po.stdout.read().decode('UTF-8').rstrip("'").lstrip("'")
200 | subprocess.check_call(["hg", "tag", "footag"], cwd=remote_path)
201 | subprocess.check_call(["touch", "test2.txt"], cwd=remote_path)
202 | subprocess.check_call(["hg", "add", "test2.txt"], cwd=remote_path)
203 | subprocess.check_call(["hg", "commit", "-m", "modified"], cwd=remote_path)
204 | po = subprocess.Popen(["hg", "log", "--template", "'{node|short}'", "-l1"], cwd=remote_path, stdout=subprocess.PIPE)
205 | self.version_end = po.stdout.read().decode('UTF-8').rstrip("'").lstrip("'")
206 |
207 | # wstool the remote repo and fake ros
208 | _add_to_file(os.path.join(self.local_path, ".rosinstall"), "- other: {local-name: ../ros}\n- hg: {local-name: clone, uri: ../remote}")
209 |
210 | cmd = ["wstool", "update"]
211 | os.chdir(self.local_path)
212 | sys.stdout = output = StringIO()
213 | wstool_main(cmd)
214 | output = output.getvalue()
215 | sys.stdout = sys.__stdout__
216 |
217 | def test_rosinstall_detailed_locapath_info(self):
218 | cmd = ["wstool", "info", "-t", "ws"]
219 | os.chdir(self.test_root_path)
220 | sys.stdout = output = StringIO()
221 | wstool_main(cmd)
222 | output = output.getvalue()
223 | tokens = _nth_line_split(-2, output)
224 | self.assertEqual(['clone', 'hg', 'default', '(-)', self.version_end, os.path.join(self.test_root_path, 'remote')], tokens)
225 |
226 | clone_path = os.path.join(self.local_path, "clone")
227 | # make local modifications check
228 | subprocess.check_call(["hg", "rm", "test2.txt"], cwd=clone_path)
229 | os.chdir(self.test_root_path)
230 | sys.stdout = output = StringIO()
231 | wstool_main(cmd)
232 | output = output.getvalue()
233 | tokens = _nth_line_split(-2, output)
234 | self.assertEqual(['clone', 'M', 'hg', 'default', '(-)', self.version_end, os.path.join(self.test_root_path, 'remote')], tokens)
235 |
236 | subprocess.check_call(["rm", ".rosinstall"], cwd=self.local_path)
237 | _add_to_file(os.path.join(self.local_path, ".rosinstall"), "- other: {local-name: ../ros}\n- hg: {local-name: clone, uri: ../remote, version: \"footag\"}")
238 | os.chdir(self.test_root_path)
239 | sys.stdout = output = StringIO()
240 | wstool_main(cmd)
241 | output = output.getvalue()
242 | tokens = _nth_line_split(-2, output)
243 | self.assertEqual(['clone', 'MV', 'hg', 'default', '(footag)', self.version_end, "(%s)" % self.version_init, os.path.join(self.test_root_path, 'remote')], tokens)
244 |
245 | subprocess.check_call(["rm", "-rf", "clone"], cwd=self.local_path)
246 | os.chdir(self.test_root_path)
247 | sys.stdout = output = StringIO()
248 | wstool_main(cmd)
249 | output = output.getvalue()
250 | tokens = _nth_line_split(-2, output)
251 | self.assertEqual(['clone', 'x', 'hg', '(footag)', os.path.join(self.test_root_path, 'remote')], tokens)
252 |
--------------------------------------------------------------------------------
/test/local/test_diff_functions_multi.py:
--------------------------------------------------------------------------------
1 | # Software License Agreement (BSD License)
2 | #
3 | # Copyright (c) 2009, Willow Garage, Inc.
4 | # All rights reserved.
5 | #
6 | # Redistribution and use in source and binary forms, with or without
7 | # modification, are permitted provided that the following conditions
8 | # are met:
9 | #
10 | # * Redistributions of source code must retain the above copyright
11 | # notice, this list of conditions and the following disclaimer.
12 | # * Redistributions in binary form must reproduce the above
13 | # copyright notice, this list of conditions and the following
14 | # disclaimer in the documentation and/or other materials provided
15 | # with the distribution.
16 | # * Neither the name of Willow Garage, Inc. nor the names of its
17 | # contributors may be used to endorse or promote products derived
18 | # from this software without specific prior written permission.
19 | #
20 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 | # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 | # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 | # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 | # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 | # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 | # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 | # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 | # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 | # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 | # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 | # POSSIBILITY OF SUCH DAMAGE.
32 |
33 | from __future__ import unicode_literals
34 |
35 | import os
36 | import sys
37 | from test.io_wrapper import StringIO
38 |
39 | import wstool
40 | import wstool.helpers
41 | import wstool.wstool_cli
42 | from wstool.wstool_cli import WstoolCLI
43 | from wstool.wstool_cli import wstool_main
44 |
45 | from test.scm_test_base import AbstractSCMTest, _add_to_file
46 |
47 | from test.local.test_diff_functions_svn import create_svn_repo, modify_svn_repo
48 | from test.local.test_diff_functions_git import create_git_repo, modify_git_repo
49 | from test.local.test_diff_functions_hg import create_hg_repo, modify_hg_repo
50 | from test.local.test_diff_functions_bzr import create_bzr_repo, modify_bzr_repo
51 |
52 |
53 | class WstoolDiffMultiTest(AbstractSCMTest):
54 |
55 | @classmethod
56 | def setUpClass(self):
57 | AbstractSCMTest.setUpClass()
58 | remote_path_svn = os.path.join(self.test_root_path, "remote_svn")
59 | remote_path_git = os.path.join(self.test_root_path, "remote_git")
60 | remote_path_bzr = os.path.join(self.test_root_path, "remote_bzr")
61 | remote_path_hg = os.path.join(self.test_root_path, "remote_hg")
62 | os.makedirs(remote_path_git)
63 | os.makedirs(remote_path_svn)
64 | os.makedirs(remote_path_hg)
65 | os.makedirs(remote_path_bzr)
66 |
67 | filler_path = os.path.join(self.test_root_path, "filler")
68 | svn_uri = "file://localhost"+remote_path_svn
69 |
70 | create_svn_repo(self.test_root_path, remote_path_svn, filler_path, svn_uri)
71 | create_git_repo(remote_path_git)
72 | create_hg_repo(remote_path_hg)
73 | create_bzr_repo(remote_path_bzr)
74 |
75 | # wstool the remote repo and fake ros (using git twice to check all overlaps)
76 | rosinstall_spec = """- other: {local-name: ../ros}
77 | - git: {local-name: clone_git, uri: ../remote_git}
78 | - svn: {local-name: clone_svn, uri: '%s'}
79 | - hg: {local-name: clone_hg, uri: ../remote_hg}
80 | - bzr: {local-name: clone_bzr, uri: ../remote_bzr}
81 | - git: {local-name: clone_git2, uri: ../remote_git}""" % svn_uri
82 |
83 | _add_to_file(os.path.join(self.local_path, ".rosinstall"), rosinstall_spec)
84 |
85 | cmd = ["rosws", "update", "-t", "ws"]
86 | os.chdir(self.test_root_path)
87 | wstool_main(cmd)
88 |
89 | clone_path_git = os.path.join(self.local_path, "clone_git")
90 | clone_path_git2 = os.path.join(self.local_path, "clone_git2")
91 | clone_path_svn = os.path.join(self.local_path, "clone_svn")
92 | clone_path_hg = os.path.join(self.local_path, "clone_hg")
93 | clone_path_bzr = os.path.join(self.local_path, "clone_bzr")
94 |
95 | modify_git_repo(clone_path_git2)
96 | modify_git_repo(clone_path_git)
97 | modify_svn_repo(clone_path_svn)
98 | modify_hg_repo(clone_path_hg)
99 | modify_bzr_repo(clone_path_bzr)
100 |
101 | def check_diff_output(self, output):
102 | # this tests that there are proper newlines between diff outputs
103 | # for svn, the order varies, so we check two known variants
104 | self.assertTrue("\nIndex: clone_svn/added.txt" in output, output)
105 | self.assertTrue("\nIndex: clone_svn/added.txt" in output, output)
106 | self.assertTrue("\nIndex: clone_svn/modified.txt" in output, output)
107 | self.assertTrue("\ndiff --git clone_hg/added.txt" in output, output)
108 | self.assertTrue("\n=== added file 'added.txt'\n--- clone_bzr/added.txt" in output, output)
109 | self.assertTrue("\ndiff --git clone_git2/added.txt" in output, output)
110 |
111 | def test_multi_diff_rosinstall_outside(self):
112 | '''Test wstool diff output from outside workspace.
113 | In particular asserts that there are newlines between diffs, and no overlaps'''
114 | cmd = ["wstool", "diff", "-t", "ws"]
115 | os.chdir(self.test_root_path)
116 | sys.stdout = output = StringIO()
117 | wstool_main(cmd)
118 | sys.stdout = sys.__stdout__
119 | output = output.getvalue()
120 | self.check_diff_output(output)
121 |
122 | def test_multi_diff_wstool_outside(self):
123 | '''Test wstool diff output from outside workspace.
124 | In particular asserts that there are newlines between diffs, and no overlaps'''
125 | cmd = ["wstool", "diff", "-t", "ws"]
126 | os.chdir(self.test_root_path)
127 | sys.stdout = output = StringIO()
128 | wstool_main(cmd)
129 | sys.stdout = sys.__stdout__
130 | output = output.getvalue()
131 | self.check_diff_output(output)
132 |
133 | cli = WstoolCLI()
134 | self.assertEqual(0, cli.cmd_diff(os.path.join(self.test_root_path, 'ws'), []))
135 |
136 | def test_multi_diff_rosinstall_inside(self):
137 | '''Test wstool diff output from inside workspace.
138 | In particular asserts that there are newlines between diffs, and no overlaps'''
139 | directory = self.test_root_path + "/ws"
140 | cmd = ["wstool", "diff"]
141 | os.chdir(directory)
142 | sys.stdout = output = StringIO()
143 | wstool_main(cmd)
144 | output = output.getvalue()
145 | self.check_diff_output(output)
146 |
147 | def test_multi_diff_wstool_inside(self):
148 | '''Test wstool diff output from inside workspace.
149 | In particular asserts that there are newlines between diffs, and no overlaps'''
150 | directory = self.test_root_path + "/ws"
151 | cmd = ["wstool", "diff"]
152 | os.chdir(directory)
153 | sys.stdout = output = StringIO()
154 | wstool_main(cmd)
155 | output = output.getvalue()
156 | sys.stdout = sys.__stdout__
157 | self.check_diff_output(output)
158 |
159 | cli = WstoolCLI()
160 | self.assertEqual(0, cli.cmd_diff(directory, []))
161 |
162 | def test_multi_status_rosinstall_inside(self):
163 | """Test wstool status output when run inside workspace.
164 | In particular asserts that there are newlines between statuses, and no overlaps"""
165 | directory = self.test_root_path + "/ws"
166 | cmd = ["wstool", "status"]
167 | os.chdir(directory)
168 | sys.stdout = output = StringIO()
169 | wstool_main(cmd)
170 | output = output.getvalue()
171 |
172 | self.assertStatusListEqual('A clone_git/added.txt\n D clone_git/deleted-fs.txt\nD clone_git/deleted.txt\n M clone_git/modified-fs.txt\nM clone_git/modified.txt\nA clone_svn/added.txt\nD clone_svn/deleted.txt\n! clone_svn/deleted-fs.txt\nM clone_svn/modified.txt\nM clone_hg/modified-fs.txt\nM clone_hg/modified.txt\nA clone_hg/added.txt\nR clone_hg/deleted.txt\n! clone_hg/deleted-fs.txt\n+N clone_bzr/added.txt\n D clone_bzr/deleted-fs.txt\n-D clone_bzr/deleted.txt\n M clone_bzr/modified-fs.txt\n M clone_bzr/modified.txt\nA clone_git2/added.txt\n D clone_git2/deleted-fs.txt\nD clone_git2/deleted.txt\n M clone_git2/modified-fs.txt\nM clone_git2/modified.txt\n', output)
173 |
174 | def test_multi_status_wstool_inside(self):
175 | """Test wstool status output when run inside workspace.
176 | In particular asserts that there are newlines between statuses, and no overlaps"""
177 | directory = self.test_root_path + "/ws"
178 | cmd = ["wstool", "status"]
179 | os.chdir(directory)
180 | sys.stdout = output = StringIO()
181 | wstool_main(cmd)
182 | output = output.getvalue()
183 | sys.stdout = sys.__stdout__
184 | self.assertStatusListEqual('A clone_git/added.txt\n D clone_git/deleted-fs.txt\nD clone_git/deleted.txt\n M clone_git/modified-fs.txt\nM clone_git/modified.txt\nA clone_svn/added.txt\nD clone_svn/deleted.txt\n! clone_svn/deleted-fs.txt\nM clone_svn/modified.txt\nM clone_hg/modified-fs.txt\nM clone_hg/modified.txt\nA clone_hg/added.txt\nR clone_hg/deleted.txt\n! clone_hg/deleted-fs.txt\n+N clone_bzr/added.txt\n D clone_bzr/deleted-fs.txt\n-D clone_bzr/deleted.txt\n M clone_bzr/modified-fs.txt\n M clone_bzr/modified.txt\nA clone_git2/added.txt\n D clone_git2/deleted-fs.txt\nD clone_git2/deleted.txt\n M clone_git2/modified-fs.txt\nM clone_git2/modified.txt\n', output)
185 |
186 | cli = WstoolCLI()
187 | self.assertEqual(0, cli.cmd_diff(directory, []))
188 |
189 | def test_multi_status_rosinstall_outside(self):
190 | """Test wstool status output when run outside workspace.
191 | In particular asserts that there are newlines between statuses, and no overlaps"""
192 | cmd = ["rosinstall", "status", "-t", "ws"]
193 | os.chdir(self.test_root_path)
194 | sys.stdout = output = StringIO()
195 | wstool_main(cmd)
196 | sys.stdout = output = StringIO()
197 | wstool_main(cmd)
198 | sys.stdout = sys.__stdout__
199 | output = output.getvalue()
200 | self.assertStatusListEqual('A clone_git/added.txt\n D clone_git/deleted-fs.txt\nD clone_git/deleted.txt\n M clone_git/modified-fs.txt\nM clone_git/modified.txt\nA clone_svn/added.txt\nD clone_svn/deleted.txt\n! clone_svn/deleted-fs.txt\nM clone_svn/modified.txt\nM clone_hg/modified-fs.txt\nM clone_hg/modified.txt\nA clone_hg/added.txt\nR clone_hg/deleted.txt\n! clone_hg/deleted-fs.txt\n+N clone_bzr/added.txt\n D clone_bzr/deleted-fs.txt\n-D clone_bzr/deleted.txt\n M clone_bzr/modified-fs.txt\n M clone_bzr/modified.txt\nA clone_git2/added.txt\n D clone_git2/deleted-fs.txt\nD clone_git2/deleted.txt\n M clone_git2/modified-fs.txt\nM clone_git2/modified.txt\n', output)
201 |
202 | def test_multi_status_wstool_outside(self):
203 | """Test wstool status output when run outside workspace.
204 | In particular asserts that there are newlines between statuses, and no overlaps"""
205 | cmd = ["wstool", "status", "-t", "ws"]
206 | os.chdir(self.test_root_path)
207 | sys.stdout = output = StringIO()
208 | wstool_main(cmd)
209 | sys.stdout = sys.__stdout__
210 | output = output.getvalue()
211 | self.assertStatusListEqual('A clone_git/added.txt\n D clone_git/deleted-fs.txt\nD clone_git/deleted.txt\n M clone_git/modified-fs.txt\nM clone_git/modified.txt\nA clone_svn/added.txt\nD clone_svn/deleted.txt\n! clone_svn/deleted-fs.txt\nM clone_svn/modified.txt\nM clone_hg/modified-fs.txt\nM clone_hg/modified.txt\nA clone_hg/added.txt\nR clone_hg/deleted.txt\n! clone_hg/deleted-fs.txt\n+N clone_bzr/added.txt\n D clone_bzr/deleted-fs.txt\n-D clone_bzr/deleted.txt\n M clone_bzr/modified-fs.txt\n M clone_bzr/modified.txt\nA clone_git2/added.txt\n D clone_git2/deleted-fs.txt\nD clone_git2/deleted.txt\n M clone_git2/modified-fs.txt\nM clone_git2/modified.txt\n', output)
212 |
213 | cli = WstoolCLI()
214 | self.assertEqual(0, cli.cmd_status(os.path.join(self.test_root_path, 'ws'), []))
215 |
216 | def test_multi_status_untracked(self):
217 | '''tests status output for --untracked.
218 | In particular asserts that there are newlines between statuses, and no overlaps'''
219 | cmd = ["wstool", "status", "-t", "ws", "--untracked"]
220 | os.chdir(self.test_root_path)
221 | sys.stdout = output = StringIO()
222 | wstool_main(cmd)
223 | sys.stdout = sys.__stdout__
224 | output = output.getvalue()
225 | self.assertStatusListEqual('A clone_git/added.txt\n D clone_git/deleted-fs.txt\nD clone_git/deleted.txt\n M clone_git/modified-fs.txt\nM clone_git/modified.txt\n?? clone_git/added-fs.txt\n? clone_svn/added-fs.txt\nA clone_svn/added.txt\nD clone_svn/deleted.txt\n! clone_svn/deleted-fs.txt\nM clone_svn/modified.txt\nM clone_hg/modified-fs.txt\nM clone_hg/modified.txt\nA clone_hg/added.txt\nR clone_hg/deleted.txt\n! clone_hg/deleted-fs.txt\n? clone_hg/added-fs.txt\n? clone_bzr/added-fs.txt\n+N clone_bzr/added.txt\n D clone_bzr/deleted-fs.txt\n-D clone_bzr/deleted.txt\n M clone_bzr/modified-fs.txt\n M clone_bzr/modified.txt\nA clone_git2/added.txt\n D clone_git2/deleted-fs.txt\nD clone_git2/deleted.txt\n M clone_git2/modified-fs.txt\nM clone_git2/modified.txt\n?? clone_git2/added-fs.txt\n', output)
226 |
227 | cmd = ["wstool", "status", "-t", "ws", "--untracked"]
228 | os.chdir(self.test_root_path)
229 | sys.stdout = output = StringIO()
230 | wstool_main(cmd)
231 | sys.stdout = sys.__stdout__
232 | output = output.getvalue()
233 | self.assertStatusListEqual('A clone_git/added.txt\n D clone_git/deleted-fs.txt\nD clone_git/deleted.txt\n M clone_git/modified-fs.txt\nM clone_git/modified.txt\n?? clone_git/added-fs.txt\n? clone_svn/added-fs.txt\nA clone_svn/added.txt\nD clone_svn/deleted.txt\n! clone_svn/deleted-fs.txt\nM clone_svn/modified.txt\nM clone_hg/modified-fs.txt\nM clone_hg/modified.txt\nA clone_hg/added.txt\nR clone_hg/deleted.txt\n! clone_hg/deleted-fs.txt\n? clone_hg/added-fs.txt\n? clone_bzr/added-fs.txt\n+N clone_bzr/added.txt\n D clone_bzr/deleted-fs.txt\n-D clone_bzr/deleted.txt\n M clone_bzr/modified-fs.txt\n M clone_bzr/modified.txt\nA clone_git2/added.txt\n D clone_git2/deleted-fs.txt\nD clone_git2/deleted.txt\n M clone_git2/modified-fs.txt\nM clone_git2/modified.txt\n?? clone_git2/added-fs.txt\n', output)
234 |
235 | cli = WstoolCLI()
236 | self.assertEqual(0, cli.cmd_status(os.path.join(self.test_root_path, 'ws'), ["--untracked"]))
237 |
--------------------------------------------------------------------------------
/test/local/test_diff_functions_svn.py:
--------------------------------------------------------------------------------
1 | # Software License Agreement (BSD License)
2 | #
3 | # Copyright (c) 2009, Willow Garage, Inc.
4 | # All rights reserved.
5 | #
6 | # Redistribution and use in source and binary forms, with or without
7 | # modification, are permitted provided that the following conditions
8 | # are met:
9 | #
10 | # * Redistributions of source code must retain the above copyright
11 | # notice, this list of conditions and the following disclaimer.
12 | # * Redistributions in binary form must reproduce the above
13 | # copyright notice, this list of conditions and the following
14 | # disclaimer in the documentation and/or other materials provided
15 | # with the distribution.
16 | # * Neither the name of Willow Garage, Inc. nor the names of its
17 | # contributors may be used to endorse or promote products derived
18 | # from this software without specific prior written permission.
19 | #
20 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 | # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 | # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 | # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 | # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 | # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 | # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 | # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 | # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 | # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 | # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 | # POSSIBILITY OF SUCH DAMAGE.
32 |
33 | from __future__ import unicode_literals
34 |
35 | import os
36 | import sys
37 | from test.io_wrapper import StringIO
38 | import subprocess
39 | import re
40 |
41 | import wstool
42 | import wstool.helpers
43 | import wstool.wstool_cli
44 | from wstool.wstool_cli import WstoolCLI
45 | from wstool.wstool_cli import wstool_main
46 |
47 | import test.scm_test_base
48 | from test.scm_test_base import AbstractSCMTest, _add_to_file, _nth_line_split
49 |
50 |
51 | def create_svn_repo(test_root_path, remote_path, filler_path, svn_uri):
52 | # create a "remote" repo
53 | subprocess.check_call(["svnadmin", "create", remote_path], cwd=test_root_path)
54 | subprocess.check_call(["svn", "checkout", svn_uri, filler_path], cwd=test_root_path)
55 | subprocess.check_call(["touch", "fixed.txt"], cwd=filler_path)
56 | subprocess.check_call(["touch", "modified.txt"], cwd=filler_path)
57 | subprocess.check_call(["touch", "modified-fs.txt"], cwd=filler_path)
58 | subprocess.check_call(["touch", "deleted.txt"], cwd=filler_path)
59 | subprocess.check_call(["touch", "deleted-fs.txt"], cwd=filler_path)
60 | subprocess.check_call(["svn", "add", "fixed.txt"], cwd=filler_path)
61 | subprocess.check_call(["svn", "add", "modified.txt"], cwd=filler_path)
62 | subprocess.check_call(["svn", "add", "modified-fs.txt"], cwd=filler_path)
63 | subprocess.check_call(["svn", "add", "deleted.txt"], cwd=filler_path)
64 | subprocess.check_call(["svn", "add", "deleted-fs.txt"], cwd=filler_path)
65 | subprocess.check_call(["svn", "commit", "-m", "modified"], cwd=filler_path)
66 |
67 |
68 | def modify_svn_repo(clone_path):
69 | # make local modifications
70 | subprocess.check_call(["rm", "deleted-fs.txt"], cwd=clone_path)
71 | subprocess.check_call(["svn", "rm", "deleted.txt"], cwd=clone_path)
72 |
73 | #_add_to_file(os.path.join(clone_path, "modified-fs.txt"), "foo\n")
74 | _add_to_file(os.path.join(clone_path, "modified.txt"), "foo\n")
75 | _add_to_file(os.path.join(clone_path, "added-fs.txt"), "tada\n")
76 | _add_to_file(os.path.join(clone_path, "added.txt"), "flam\n")
77 | subprocess.check_call(["svn", "add", "--no-auto-props", "added.txt"], cwd=clone_path)
78 |
79 |
80 | class WstoolDiffSvnTest(AbstractSCMTest):
81 |
82 | @classmethod
83 | def setUpClass(self):
84 | AbstractSCMTest.setUpClass()
85 | remote_path = os.path.join(self.test_root_path, "remote")
86 | filler_path = os.path.join(self.test_root_path, "filler")
87 |
88 | svn_uri = "file://localhost" + remote_path
89 |
90 | create_svn_repo(self.test_root_path, remote_path, filler_path, svn_uri)
91 |
92 | # wstool the remote repo and fake ros
93 | _add_to_file(os.path.join(self.local_path, ".rosinstall"), "- other: {local-name: ../ros}\n- svn: {local-name: clone, uri: '" + svn_uri + "'}")
94 |
95 | cmd = ["wstool", "update", "-t", "ws"]
96 | os.chdir(self.test_root_path)
97 | wstool_main(cmd)
98 | clone_path = os.path.join(self.local_path, "clone")
99 |
100 | modify_svn_repo(clone_path)
101 |
102 | def check_diff_output(self, output):
103 | # svn 1.9 added the "nonexistent" output, replace it with the
104 | # revision 0 that the test results expect.
105 | output_fixed = re.sub("\(nonexistent\)", "(revision 0)", output)
106 | # svn output order varies between versions
107 | expected = ["""\
108 | Index: clone/added.txt
109 | ===================================================================
110 | --- clone/added.txt\t(revision 0)
111 | +++ clone/added.txt\t""",
112 | """@@ -0,0 +1 @@
113 | +flam""",
114 | """\
115 | Index: clone/modified.txt
116 | ===================================================================
117 | --- clone/modified.txt\t(revision 1)
118 | +++ clone/modified.txt\t(working copy)
119 | @@ -0,0 +1 @@
120 | +foo"""]
121 | for snippet in expected:
122 | for line in snippet.splitlines():
123 | # assertIn is not supported in Python2.6
124 | self.assertTrue(line in output_fixed, output)
125 |
126 | def test_wstool_diff_svn_outside(self):
127 | """Test diff output for svn when run outside workspace"""
128 |
129 | cmd = ["wstool", "diff", "-t", "ws"]
130 | os.chdir(self.test_root_path)
131 | sys.stdout = output = StringIO()
132 | wstool_main(cmd)
133 | sys.stdout = sys.__stdout__
134 | output = output.getvalue()
135 | self.check_diff_output(output)
136 |
137 | cli = WstoolCLI()
138 | self.assertEqual(0, cli.cmd_diff(os.path.join(self.test_root_path, 'ws'), []))
139 |
140 | def test_wstool_diff_svn_inside(self):
141 | """Test diff output for svn when run inside workspace"""
142 | directory = self.test_root_path + "/ws"
143 |
144 | cmd = ["wstool", "diff"]
145 | os.chdir(directory)
146 | sys.stdout = output = StringIO()
147 | wstool_main(cmd)
148 | output = output.getvalue()
149 | sys.stdout = sys.__stdout__
150 | self.check_diff_output(output)
151 |
152 | cli = WstoolCLI()
153 | self.assertEqual(0, cli.cmd_status(directory, []))
154 |
155 | def test_wstool_status_svn_inside(self):
156 | """Test status output for svn when run inside workspace"""
157 | directory = self.test_root_path + "/ws"
158 |
159 | cmd = ["wstool", "status"]
160 | os.chdir(directory)
161 | sys.stdout = output = StringIO()
162 | wstool_main(cmd)
163 | output = output.getvalue()
164 | sys.stdout = sys.__stdout__
165 |
166 | self.assertStatusListEqual('A clone/added.txt\nD clone/deleted.txt\n! clone/deleted-fs.txt\nM clone/modified.txt\n', output)
167 |
168 | cli = WstoolCLI()
169 | self.assertEqual(0, cli.cmd_diff(directory, []))
170 |
171 | def test_wstool_status_svn_outside(self):
172 | """Test status output for svn when run outside workspace"""
173 |
174 | cmd = ["wstool", "status", "-t", "ws"]
175 | os.chdir(self.test_root_path)
176 | sys.stdout = output = StringIO()
177 | wstool_main(cmd)
178 | sys.stdout = sys.__stdout__
179 | output = output.getvalue()
180 | self.assertStatusListEqual('A clone/added.txt\nD clone/deleted.txt\n! clone/deleted-fs.txt\nM clone/modified.txt\n', output)
181 |
182 | cli = WstoolCLI()
183 | self.assertEqual(0, cli.cmd_status(os.path.join(self.test_root_path, 'ws'), []))
184 |
185 | def test_wstool_status_svn_untracked(self):
186 | """Test status output for svn when run outside workspace"""
187 |
188 | cmd = ["wstool", "status", "-t", "ws", "--untracked"]
189 | os.chdir(self.test_root_path)
190 | sys.stdout = output = StringIO()
191 | wstool_main(cmd)
192 | sys.stdout = sys.__stdout__
193 | output = output.getvalue()
194 | self.assertStatusListEqual('? clone/added-fs.txt\nA clone/added.txt\nD clone/deleted.txt\n! clone/deleted-fs.txt\nM clone/modified.txt\n', output)
195 |
196 | cli = WstoolCLI()
197 | self.assertEqual(0, cli.cmd_status(os.path.join(self.test_root_path, 'ws'), ["--untracked"]))
198 |
199 | def test_wstool_info_svn(self):
200 | cmd = ["wstool", "info", "-t", "ws"]
201 | os.chdir(self.test_root_path)
202 | sys.stdout = output = StringIO()
203 | wstool_main(cmd)
204 | output = output.getvalue()
205 | tokens = _nth_line_split(-2, output)
206 | self.assertEqual(['clone', 'M', 'svn'], tokens[0:3])
207 |
208 | cli = WstoolCLI()
209 | self.assertEqual(0, cli.cmd_info(os.path.join(self.test_root_path, 'ws'), []))
210 |
211 |
212 | class WstoolInfoSvnTest(AbstractSCMTest):
213 |
214 | def setUp(self):
215 | AbstractSCMTest.setUp(self)
216 | remote_path = os.path.join(self.test_root_path, "remote")
217 | filler_path = os.path.join(self.test_root_path, "filler")
218 | self.svn_uri = "file://localhost" + remote_path
219 |
220 | # create a "remote" repo
221 | subprocess.check_call(["svnadmin", "create", remote_path], cwd=self.test_root_path)
222 | subprocess.check_call(["svn", "checkout", self.svn_uri, filler_path], cwd=self.test_root_path)
223 | subprocess.check_call(["touch", "test.txt"], cwd=filler_path)
224 | subprocess.check_call(["svn", "add", "test.txt"], cwd=filler_path)
225 | subprocess.check_call(["svn", "commit", "-m", "modified"], cwd=filler_path)
226 | subprocess.check_call(["touch", "test2.txt"], cwd=filler_path)
227 | subprocess.check_call(["svn", "add", "test2.txt"], cwd=filler_path)
228 | subprocess.check_call(["svn", "commit", "-m", "modified"], cwd=filler_path)
229 |
230 | self.version_init = "-r1"
231 | self.version_end = "-r2"
232 |
233 | # wstool the remote repo and fake ros
234 | _add_to_file(os.path.join(self.local_path, ".rosinstall"), "- other: {local-name: ../ros}\n- svn: {local-name: clone, uri: '" + self.svn_uri + "'}")
235 |
236 | cmd = ["wstool", "update"]
237 | os.chdir(self.local_path)
238 | sys.stdout = output = StringIO()
239 | wstool_main(cmd)
240 | output = output.getvalue()
241 | sys.stdout = sys.__stdout__
242 |
243 | def test_rosinstall_detailed_locapath_info(self):
244 | cmd = ["wstool", "info", "-t", "ws"]
245 | os.chdir(self.test_root_path)
246 | sys.stdout = output = StringIO()
247 | wstool_main(cmd)
248 | output = output.getvalue()
249 | tokens = _nth_line_split(-2, output)
250 | self.assertEqual(['clone', 'svn', self.version_end, self.svn_uri], tokens)
251 |
252 | clone_path = os.path.join(self.local_path, "clone")
253 | # make local modifications check
254 | subprocess.check_call(["touch", "test3.txt"], cwd=clone_path)
255 | subprocess.check_call(["svn", "add", "test3.txt"], cwd=clone_path)
256 | os.chdir(self.test_root_path)
257 | sys.stdout = output = StringIO()
258 | wstool_main(cmd)
259 | output = output.getvalue()
260 | tokens = _nth_line_split(-2, output)
261 | self.assertEqual(['clone', 'M', 'svn', self.version_end, self.svn_uri], tokens)
262 |
263 | subprocess.check_call(["rm", ".rosinstall"], cwd=self.local_path)
264 | _add_to_file(os.path.join(self.local_path, ".rosinstall"), "- other: {local-name: ../ros}\n- svn: {local-name: clone, uri: '" + self.svn_uri + "', version: \"1\"}")
265 | os.chdir(self.test_root_path)
266 | sys.stdout = output = StringIO()
267 | wstool_main(cmd)
268 | output = output.getvalue()
269 | tokens = _nth_line_split(-2, output)
270 | self.assertEqual(['clone', 'MV', 'svn', '1', '(-)', self.version_end, "(%s)" % self.version_init, self.svn_uri], tokens)
271 |
272 | subprocess.check_call(["rm", "-rf", "clone"], cwd=self.local_path)
273 | os.chdir(self.test_root_path)
274 | sys.stdout = output = StringIO()
275 | wstool_main(cmd)
276 | output = output.getvalue()
277 | tokens = _nth_line_split(-2, output)
278 | self.assertEqual(['clone', 'x', 'svn', '(-)', self.svn_uri], tokens)
279 |
--------------------------------------------------------------------------------
/test/local/test_export.py:
--------------------------------------------------------------------------------
1 | # Software License Agreement (BSD License)
2 | #
3 | # Copyright (c) 2009, Willow Garage, Inc.
4 | # All rights reserved.
5 | #
6 | # Redistribution and use in source and binary forms, with or without
7 | # modification, are permitted provided that the following conditions
8 | # are met:
9 | #
10 | # * Redistributions of source code must retain the above copyright
11 | # notice, this list of conditions and the following disclaimer.
12 | # * Redistributions in binary form must reproduce the above
13 | # copyright notice, this list of conditions and the following
14 | # disclaimer in the documentation and/or other materials provided
15 | # with the distribution.
16 | # * Neither the name of Willow Garage, Inc. nor the names of its
17 | # contributors may be used to endorse or promote products derived
18 | # from this software without specific prior written permission.
19 | #
20 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 | # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 | # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 | # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 | # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 | # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 | # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 | # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 | # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 | # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 | # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 | # POSSIBILITY OF SUCH DAMAGE.
32 |
33 | import datetime
34 | import os
35 | import sys
36 | import subprocess
37 |
38 | from test.io_wrapper import StringIO
39 |
40 | from wstool.wstool_cli import wstool_main
41 |
42 | from test.scm_test_base import AbstractSCMTest, _add_to_file, get_git_hash
43 | from test.local.test_diff_functions_git import create_git_repo, modify_git_repo
44 |
45 |
46 | class WstoolExportTest(AbstractSCMTest):
47 |
48 | @classmethod
49 | def setUpClass(self):
50 | AbstractSCMTest.setUpClass()
51 | self.remote_path = os.path.join(self.test_root_path, 'remote')
52 | self.new_remote_path = os.path.join(self.test_root_path, 'fooo')
53 | self.version = 'master'
54 | self.branch = 'test_branch'
55 | self.date = datetime.date.today().isoformat()
56 | os.makedirs(self.remote_path)
57 |
58 | create_git_repo(self.remote_path)
59 |
60 | # wstool the remote repo and fake ros
61 | entry = '''\
62 | - other: {local-name: ../ros}
63 | - git: {local-name: clone, uri: ../remote, version: %s}
64 | ''' % self.version
65 | _add_to_file(os.path.join(self.local_path, '.rosinstall'), entry)
66 |
67 | cmd = ['wstool', 'update', '-t', 'ws']
68 | os.chdir(self.test_root_path)
69 | wstool_main(cmd)
70 |
71 | self.clone_path = os.path.join(self.local_path, 'clone')
72 |
73 | modify_git_repo(self.clone_path)
74 |
75 | subprocess.check_call(['git', 'checkout', '-b', self.branch],
76 | cwd=self.clone_path)
77 | subprocess.check_call(['git', 'remote', 'set-url', 'origin',
78 | self.new_remote_path], cwd=self.clone_path)
79 |
80 | @staticmethod
81 | def exp(*args):
82 | return '''\
83 | # THIS IS AN AUTOGENERATED FILE, LAST GENERATED USING wstool ON %s
84 | - git:
85 | local-name: clone
86 | uri: %s
87 | version: %s
88 |
89 | ''' % args
90 |
91 | def helper(self, spec, exact, expected_output):
92 | cmd = ['wstool', 'export', '-t', 'ws']
93 | if spec:
94 | cmd += ['--spec']
95 | if exact:
96 | cmd += ['--exact']
97 |
98 | os.chdir(self.test_root_path)
99 | sys.stdout = output = StringIO()
100 | wstool_main(cmd)
101 | sys.stdout = sys.__stdout__
102 | output = output.getvalue().encode('utf-8')
103 | expected_output = expected_output.encode('utf-8')
104 | self.assertEqual(expected_output, output)
105 |
106 | def test_wstool_export(self):
107 | o = self.exp(self.date, self.new_remote_path, self.branch)
108 | self.helper(False, False, o)
109 |
110 | def test_wstool_export_spec(self):
111 | o = self.exp(self.date, self.remote_path, self.version)
112 | self.helper(True, False, o)
113 |
114 | def test_wstool_export_exact(self):
115 | uuid = get_git_hash(self.clone_path)
116 | o = self.exp(self.date, self.new_remote_path, uuid)
117 | self.helper(False, True, o)
118 |
119 | def test_wstool_export_spec_exact(self):
120 | uuid = get_git_hash(self.clone_path)
121 | o = self.exp(self.date, self.remote_path, uuid)
122 | self.helper(True, True, o)
123 |
--------------------------------------------------------------------------------
/test/local/test_interation.py:
--------------------------------------------------------------------------------
1 | # Software License Agreement (BSD License)
2 | #
3 | # Copyright (c) 2009, Willow Garage, Inc.
4 | # All rights reserved.
5 | #
6 | # Redistribution and use in source and binary forms, with or without
7 | # modification, are permitted provided that the following conditions
8 | # are met:
9 | #
10 | # * Redistributions of source code must retain the above copyright
11 | # notice, this list of conditions and the following disclaimer.
12 | # * Redistributions in binary form must reproduce the above
13 | # copyright notice, this list of conditions and the following
14 | # disclaimer in the documentation and/or other materials provided
15 | # with the distribution.
16 | # * Neither the name of Willow Garage, Inc. nor the names of its
17 | # contributors may be used to endorse or promote products derived
18 | # from this software without specific prior written permission.
19 | #
20 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 | # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 | # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 | # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 | # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 | # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 | # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 | # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 | # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 | # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 | # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 | # POSSIBILITY OF SUCH DAMAGE.
32 |
33 | import os
34 |
35 | import wstool
36 | import wstool.multiproject_cmd
37 | import wstool.ui
38 |
39 |
40 | from test.scm_test_base import AbstractFakeRosBasedTest, _create_yaml_file, _create_config_elt_dict
41 |
42 |
43 | class FakeUi(wstool.ui.Ui):
44 | def __init__(self, path='', mode='skip', prompt_result='y'):
45 | self.path = path
46 | self.mode = mode
47 |
48 | def get_backup_path(self):
49 | return path
50 |
51 | def prompt_del_abort_retry(self, prompt, allow_skip=False):
52 | return mode
53 |
54 | def get_input(self, prompt):
55 | return prompt_result
56 |
57 |
58 | class RosinstallInteractive(AbstractFakeRosBasedTest):
59 | """tests with possible User Interaction, using mock to simulate user input"""
60 |
61 | def setUp(self):
62 | self.old_ui = wstool.ui.Ui.get_ui()
63 | wstool.ui.Ui.set_ui(FakeUi())
64 |
65 | def tearDown(self):
66 | wstool.ui.Ui.set_ui(self.old_ui)
67 |
68 | def test_twice_with_relpath(self):
69 | """runs wstool with generated self.simple_rosinstall to create local wstool env
70 | and creates a directory for a second local wstool env"""
71 | AbstractFakeRosBasedTest.setUp(self)
72 |
73 | self.rel_uri_rosinstall = os.path.join(self.test_root_path, "rel_uri.rosinstall")
74 | _create_yaml_file([_create_config_elt_dict("git", "ros", self.ros_path),
75 | _create_config_elt_dict("git", "gitrepo", os.path.relpath(self.git_path, self.directory))],
76 | self.rel_uri_rosinstall)
77 |
78 | config = wstool.multiproject_cmd.get_config(self.directory, [self.rel_uri_rosinstall, self.ros_path])
79 | wstool.multiproject_cmd.cmd_info(config)
80 | wstool.multiproject_cmd.cmd_find_unmanaged_repos
81 | wstool.multiproject_cmd.cmd_install_or_update(config)
82 |
83 | config = wstool.multiproject_cmd.get_config(self.directory, [self.rel_uri_rosinstall, self.ros_path])
84 | wstool.multiproject_cmd.cmd_install_or_update(config)
85 |
86 | self.rel_uri_rosinstall2 = os.path.join(self.test_root_path, "rel_uri.wstool2")
87 | # switch URIs to confuse config
88 | _create_yaml_file([_create_config_elt_dict("git", "ros", os.path.relpath(self.git_path, self.directory)),
89 | _create_config_elt_dict("git", "gitrepo", self.ros_path)],
90 | self.rel_uri_rosinstall2)
91 |
92 | config = wstool.multiproject_cmd.get_config(self.directory, [self.rel_uri_rosinstall, self.ros_path])
93 | wstool.multiproject_cmd.cmd_install_or_update(config)
94 |
--------------------------------------------------------------------------------
/test/local/test_multiproject_functions.py:
--------------------------------------------------------------------------------
1 | # Software License Agreement (BSD License)
2 | #
3 | # Copyright (c) 2009, Willow Garage, Inc.
4 | # All rights reserved.
5 | #
6 | # Redistribution and use in source and binary forms, with or without
7 | # modification, are permitted provided that the following conditions
8 | # are met:
9 | #
10 | # * Redistributions of source code must retain the above copyright
11 | # notice, this list of conditions and the following disclaimer.
12 | # * Redistributions in binary form must reproduce the above
13 | # copyright notice, this list of conditions and the following
14 | # disclaimer in the documentation and/or other materials provided
15 | # with the distribution.
16 | # * Neither the name of Willow Garage, Inc. nor the names of its
17 | # contributors may be used to endorse or promote products derived
18 | # from this software without specific prior written permission.
19 | #
20 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 | # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 | # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 | # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 | # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 | # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 | # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 | # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 | # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 | # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 | # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 | # POSSIBILITY OF SUCH DAMAGE.
32 |
33 | import os
34 | import unittest
35 |
36 | from wstool.common import DistributedWork, WorkerThread, normabspath,\
37 | is_web_uri, select_elements, select_element, normalize_uri, realpath_relation,\
38 | conditional_abspath, string_diff, MultiProjectException
39 |
40 |
41 | class FooThing:
42 | def __init__(self, el, result=None):
43 | self.element = el
44 | self.done = False
45 | self.result = result
46 |
47 | def do_work(self):
48 | self.done = True
49 | return self.result
50 |
51 | def get_path_spec(self):
52 | return self.element
53 |
54 | def get_local_name(self):
55 | return 'bar'
56 |
57 |
58 | class MockElement:
59 | def __init__(self, localname, path):
60 | self.localname = localname
61 | self.path = path
62 |
63 | def get_local_name(self):
64 | return self.localname
65 |
66 | def get_path(self):
67 | return self.path
68 |
69 |
70 | class FunctionsTest(unittest.TestCase):
71 |
72 | def test_normabspath(self):
73 | base = "/foo/bar"
74 | self.assertEqual("/foo/bar", normabspath('.', base))
75 | self.assertEqual("/foo/bar", normabspath('foo/..', base))
76 | self.assertEqual("/foo/bar", normabspath(base, base))
77 | self.assertEqual("/foo", normabspath("/foo", base))
78 | self.assertEqual("/foo/bar/bim", normabspath('bim', base))
79 | self.assertEqual("/foo", normabspath('..', base))
80 |
81 | def test_is_web_uri(self):
82 | self.assertTrue(is_web_uri('http://foo.com'))
83 | self.assertTrue(is_web_uri('http://foo.com/bar'))
84 | self.assertTrue(is_web_uri('http://foo.com:42'))
85 | self.assertTrue(is_web_uri('http://foo.com:42/bar'))
86 | self.assertTrue(is_web_uri('ssh://foo.com'))
87 | self.assertTrue(is_web_uri('lp:foo.com'))
88 | self.assertTrue(is_web_uri('git://foo.com'))
89 | self.assertTrue(is_web_uri('git+ssh://foo.com:foo'))
90 | self.assertTrue(is_web_uri('user@foo:foo/bar'))
91 | self.assertFalse(is_web_uri('foo/bar'))
92 | self.assertFalse(is_web_uri('bar'))
93 | self.assertFalse(is_web_uri(''))
94 | self.assertFalse(is_web_uri(None))
95 |
96 | def test_normalize_uri(self):
97 | self.assertEqual('/foo', normalize_uri('/foo', None))
98 | self.assertEqual(None, normalize_uri(None, None))
99 | self.assertEqual('/bar/foo', normalize_uri('foo', '/bar'))
100 | self.assertEqual('http://foo.com', normalize_uri('http://foo.com', None))
101 |
102 | def test_string_diff(self):
103 | self.assertEqual('', string_diff(None, None))
104 | self.assertEqual('foo', string_diff('foo', 'foo'))
105 | self.assertEqual('foo3', string_diff('foo', 'foo3'))
106 | self.assertEqual(
107 | '...7890foo3',
108 | string_diff('12345678901234567890foo',
109 | '12345678901234567890foo3'))
110 | self.assertEqual(
111 | '...7890foo3',
112 | string_diff('12345678901234567890foo4',
113 | '12345678901234567890foo3'))
114 | self.assertEqual(
115 | '...7890foo3',
116 | string_diff('12345678901234567890foo45',
117 | '12345678901234567890foo3'))
118 | self.assertEqual(
119 | '...4567890foo123456789123456789',
120 | string_diff('12345678901234567890',
121 | '12345678901234567890foo123456789123456789'))
122 |
123 | self.assertEqual("['foo']", string_diff(['foo'], ['foo']))
124 | self.assertEqual("['bar']", string_diff(['foo'], ['bar']))
125 |
126 | def test_conditional_abspath(self):
127 | path = "foo"
128 | self.assertEqual(os.path.normpath(os.path.join(os.getcwd(), path)), conditional_abspath(path))
129 | path = "http://someuri.com"
130 | self.assertEqual("http://someuri.com", conditional_abspath(path))
131 |
132 | def test_abspath_overlap(self):
133 | base = "/foo/bar"
134 | # simple
135 | self.assertEqual('SAME_AS', realpath_relation("/foo", "/foo"))
136 | self.assertEqual('SAME_AS', realpath_relation("/", "/"))
137 | # denormalized
138 | self.assertEqual('SAME_AS', realpath_relation("/foo/.", "/foo/bar/../"))
139 | # subdir
140 | self.assertEqual('PARENT_OF', realpath_relation("/foo", "/foo/bar/baz/bam"))
141 | self.assertEqual('CHILD_OF', realpath_relation("/foo/bar/baz/bam", "/foo"))
142 | ## Negatives
143 | self.assertEqual(None, realpath_relation("/foo", "/bar"))
144 | self.assertEqual(None, realpath_relation("/foo", "/foo2"))
145 | self.assertEqual(None, realpath_relation("/foo/bar", "/foo/ba"))
146 | self.assertEqual(None, realpath_relation("/foo/ba", "/foo/bar/baz"))
147 | self.assertEqual(None, realpath_relation("/foo/bar/baz", "/foo/ba"))
148 |
149 | def test_select_element(self):
150 | self.assertEqual(None, select_element(None, None))
151 | self.assertEqual(None, select_element([], None))
152 | mock1 = MockElement('foo', '/test/path1')
153 | mock2 = MockElement('bar', '/test/path2')
154 | mock3 = MockElement('baz', '/test/path3')
155 | self.assertEqual(None, select_element([], 'pin'))
156 | self.assertEqual(None, select_element([mock1], 'pin'))
157 | self.assertEqual(None, select_element([mock1, mock3], 'pin'))
158 |
159 | self.assertEqual('bar', select_element([mock1, mock2, mock3], 'bar').get_local_name())
160 | self.assertEqual('bar', select_element([mock1, mock2, mock3], '/test/path2').get_local_name())
161 | self.assertEqual('bar', select_element([mock1, mock2, mock3], '/test/../foo/../test/path2/').get_local_name())
162 |
163 | def test_worker_thread(self):
164 | try:
165 | w = WorkerThread(None, None, None)
166 | self.fail("expected Exception")
167 | except MultiProjectException:
168 | pass
169 | try:
170 | w = WorkerThread(FooThing(el=None), 2, 3)
171 | self.fail("expected Exception")
172 | except MultiProjectException:
173 | pass
174 | thing = FooThing(FooThing(None))
175 | result = [None]
176 | w = WorkerThread(thing, result, 0)
177 | self.assertEqual(thing.done, False)
178 | w.run()
179 | self.assertEqual(thing.done, True, result)
180 | self.assertEqual(True, 'error' in result[0])
181 |
182 | thing = FooThing(FooThing(None), result={'done': True})
183 | result = [None]
184 | w = WorkerThread(thing, result, 0)
185 | self.assertEqual(thing.done, False)
186 | w.run()
187 | self.assertEqual(thing.done, True, result)
188 | self.assertEqual(False, 'error' in result[0], result)
189 |
190 | def test_distributed_work_init(self):
191 | work = DistributedWork(capacity=200)
192 | self.assertEqual(10, work.num_threads)
193 | work = DistributedWork(capacity=3, num_threads=5)
194 | self.assertEqual(3, work.num_threads)
195 | work = DistributedWork(capacity=5, num_threads=3)
196 | self.assertEqual(3, work.num_threads)
197 | work = DistributedWork(capacity=3, num_threads=-1)
198 | self.assertEqual(3, work.num_threads)
199 |
200 | def test_distributed_work(self):
201 | work = DistributedWork(3)
202 |
203 | thing1 = FooThing(FooThing(FooThing(None)), result={'done': True})
204 | thing2 = FooThing(FooThing(FooThing(None)), result={'done': True})
205 | thing3 = FooThing(FooThing(FooThing(None)), result={'done': True})
206 | self.assertEqual(3, len(work.outputs))
207 | work.add_thread(thing1)
208 | self.assertEqual(1, len(work.threads))
209 | work.add_thread(thing2)
210 | self.assertEqual(2, len(work.threads))
211 | work.add_thread(thing3)
212 | self.assertEqual(3, len(work.threads))
213 | self.assertEqual(thing1.done, False)
214 | self.assertEqual(thing2.done, False)
215 | self.assertEqual(thing3.done, False)
216 | output = work.run()
217 | self.assertEqual(False, 'error' in output[0], output)
218 | self.assertEqual(False, 'error' in output[1], output)
219 | self.assertEqual(False, 'error' in output[2], output)
220 |
221 | def test_select_elements(self):
222 | self.assertEqual([], select_elements(None, None))
223 | mock1 = MockElement('foo', '/test/path1')
224 | mock2 = MockElement('bar', '/test/path2')
225 | mock3 = MockElement('baz', '/test/path3')
226 |
227 | class FakeConfig():
228 | def get_config_elements(self):
229 | return [mock1, mock2, mock3]
230 |
231 | def get_base_path(self):
232 | return '/foo/bar'
233 | self.assertEqual([mock1, mock2, mock3],
234 | select_elements(FakeConfig(), None))
235 | self.assertEqual([mock2],
236 | select_elements(FakeConfig(), ['bar']))
237 | self.assertEqual([mock1, mock2, mock3],
238 | select_elements(FakeConfig(), ['/foo/bar']))
239 | self.assertRaises(MultiProjectException, select_elements, FakeConfig(), ['bum'])
240 | self.assertRaises(MultiProjectException, select_elements, FakeConfig(), ['foo', 'bum', 'bar'])
241 | self.assertRaises(MultiProjectException, select_elements, FakeConfig(), ['bu*'])
242 |
--------------------------------------------------------------------------------
/test/local/test_rosinstall_options.py:
--------------------------------------------------------------------------------
1 | # Software License Agreement (BSD License)
2 | #
3 | # Copyright (c) 2009, Willow Garage, Inc.
4 | # All rights reserved.
5 | #
6 | # Redistribution and use in source and binary forms, with or without
7 | # modification, are permitted provided that the following conditions
8 | # are met:
9 | #
10 | # * Redistributions of source code must retain the above copyright
11 | # notice, this list of conditions and the following disclaimer.
12 | # * Redistributions in binary form must reproduce the above
13 | # copyright notice, this list of conditions and the following
14 | # disclaimer in the documentation and/or other materials provided
15 | # with the distribution.
16 | # * Neither the name of Willow Garage, Inc. nor the names of its
17 | # contributors may be used to endorse or promote products derived
18 | # from this software without specific prior written permission.
19 | #
20 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 | # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 | # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 | # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 | # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 | # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 | # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 | # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 | # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 | # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 | # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 | # POSSIBILITY OF SUCH DAMAGE.
32 |
33 | import os
34 | import copy
35 | import tempfile
36 |
37 | import wstool
38 | from wstool.wstool_cli import wstool_main
39 | from wstool.common import MultiProjectException
40 |
41 | from test.scm_test_base import AbstractFakeRosBasedTest, _create_yaml_file, _create_config_elt_dict, _create_git_repo
42 |
43 |
44 | class RosinstallOptionsTest(AbstractFakeRosBasedTest):
45 | """Test command line option for failure behavior"""
46 |
47 | @classmethod
48 | def setUpClass(self):
49 | AbstractFakeRosBasedTest.setUpClass()
50 |
51 | # create another repo in git
52 | self.git_path2 = os.path.join(self.test_root_path, "gitrepo2")
53 | _create_git_repo(self.git_path2)
54 | self.simple_changed_uri_rosinstall = os.path.join(self.test_root_path, "simple_changed_uri.rosinstall")
55 | # same local name for gitrepo, different uri
56 | _create_yaml_file([_create_config_elt_dict("git", "ros", self.ros_path),
57 | _create_config_elt_dict("git", "gitrepo", self.git_path2)],
58 | self.simple_changed_uri_rosinstall)
59 |
60 | # create a broken config
61 | self.broken_rosinstall = os.path.join(self.test_root_path, "broken.rosinstall")
62 | _create_yaml_file([_create_config_elt_dict("other", self.ros_path),
63 | _create_config_elt_dict("hg", "hgrepo", self.hg_path + "invalid")],
64 | self.broken_rosinstall)
65 |
66 | def test_Rosinstall_help(self):
67 | cmd = copy.copy(self.wstool_fn)
68 | cmd.append("-h")
69 | self.assertEqual(0, wstool_main(cmd))
70 |
71 | def test_rosinstall_delete_changes(self):
72 | cmd = copy.copy(self.wstool_fn)
73 | cmd.extend(["init", self.directory, self.simple_rosinstall])
74 | self.assertEqual(0, wstool_main(cmd))
75 | cmd = copy.copy(self.wstool_fn)
76 | cmd.extend(["merge", "-t", self.directory, self.simple_changed_uri_rosinstall, "--merge-replace", "-y"])
77 | self.assertEqual(0, wstool_main(cmd))
78 | cmd = copy.copy(self.wstool_fn)
79 | cmd.extend(["update", "-t", self.directory, "--delete-changed-uri"])
80 | self.assertEqual(0, wstool_main(cmd))
81 |
82 | def test_rosinstall_abort_changes(self):
83 | cmd = copy.copy(self.wstool_fn)
84 | cmd.extend(["init", self.directory, self.simple_rosinstall])
85 | self.assertEqual(0, wstool_main(cmd))
86 | cmd = copy.copy(self.wstool_fn)
87 | cmd.extend(["merge", "-t", self.directory, self.simple_changed_uri_rosinstall, "--merge-replace", "-y"])
88 | self.assertEqual(0, wstool_main(cmd))
89 | cmd = copy.copy(self.wstool_fn)
90 | cmd.extend(["update", "-t", self.directory, "--abort-changed-uri"])
91 | try:
92 | wstool_main(cmd)
93 | self.fail("expected exception")
94 | except MultiProjectException:
95 | pass
96 |
97 | def test_rosinstall_backup_changes(self):
98 | cmd = copy.copy(self.wstool_fn)
99 | cmd.extend(["init", self.directory, self.simple_rosinstall])
100 | self.assertEqual(0, wstool_main(cmd))
101 | directory1 = tempfile.mkdtemp()
102 | self.directories["backup1"] = directory1
103 | cmd = copy.copy(self.wstool_fn)
104 | cmd.extend(["merge", "-t", self.directory, self.simple_changed_uri_rosinstall, "--merge-replace", "-y"])
105 | self.assertEqual(0, wstool_main(cmd))
106 | cmd = copy.copy(self.wstool_fn)
107 | cmd.extend(["update", "-t", self.directory, "--backup-changed-uri=%s" % directory1])
108 | self.assertEqual(0, wstool_main(cmd))
109 | self.assertEqual(len(os.listdir(directory1)), 1)
110 |
111 | def test_rosinstall_change_vcs_type(self):
112 | cmd = copy.copy(self.wstool_fn)
113 | cmd.extend(["init", self.directory, self.simple_rosinstall])
114 | self.assertEqual(0, wstool_main(cmd))
115 | cmd = copy.copy(self.wstool_fn)
116 | cmd.extend(["merge", "-t", self.directory, self.simple_changed_vcs_rosinstall, "--merge-replace", "-y"])
117 | self.assertEqual(0, wstool_main(cmd))
118 | cmd = copy.copy(self.wstool_fn)
119 | cmd.extend(["update", "-t", self.directory, "--delete-changed-uri"])
120 | self.assertEqual(0, wstool_main(cmd))
121 |
122 | def test_rosinstall_invalid_fail(self):
123 | cmd = copy.copy(self.wstool_fn)
124 | cmd.extend([self.directory, "init", self.broken_rosinstall])
125 | try:
126 | wstool_main(cmd)
127 | self.fail("expected exception")
128 | except MultiProjectException:
129 | pass
130 |
131 | def test_rosinstall_invalid_continue(self):
132 | cmd = copy.copy(self.wstool_fn)
133 | cmd.extend(["-t", self.directory, "merge", self.broken_rosinstall, "--continue-on-error"])
134 | self.assertTrue(wstool_main(cmd))
135 |
--------------------------------------------------------------------------------
/test/local/test_rosinstall_standalone_functions.py:
--------------------------------------------------------------------------------
1 | # Software License Agreement (BSD License)
2 | #
3 | # Copyright (c) 2009, Willow Garage, Inc.
4 | # All rights reserved.
5 | #
6 | # Redistribution and use in source and binary forms, with or without
7 | # modification, are permitted provided that the following conditions
8 | # are met:
9 | #
10 | # * Redistributions of source code must retain the above copyright
11 | # notice, this list of conditions and the following disclaimer.
12 | # * Redistributions in binary form must reproduce the above
13 | # copyright notice, this list of conditions and the following
14 | # disclaimer in the documentation and/or other materials provided
15 | # with the distribution.
16 | # * Neither the name of Willow Garage, Inc. nor the names of its
17 | # contributors may be used to endorse or promote products derived
18 | # from this software without specific prior written permission.
19 | #
20 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 | # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 | # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 | # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 | # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 | # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 | # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 | # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 | # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 | # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 | # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 | # POSSIBILITY OF SUCH DAMAGE.
32 |
33 | import os
34 | import unittest
35 | import subprocess
36 |
37 | import wstool.helpers
38 | from wstool.config import Config
39 | from wstool.config_yaml import PathSpec
40 |
41 | from mock import Mock
42 |
43 |
44 | class FunctionsTest(unittest.TestCase):
45 |
46 | def test_get_ros_package_path(self):
47 | config = Config([PathSpec("foo"),
48 | PathSpec("bar")],
49 | ".",
50 | None)
51 | self.assertEqual(list(map(os.path.abspath, ['bar',
52 | 'foo'])),
53 | wstool.helpers.get_ros_package_path(config))
54 |
--------------------------------------------------------------------------------
/test/local/test_shallow_checkout_git.py:
--------------------------------------------------------------------------------
1 | # Software License Agreement (BSD License)
2 | #
3 | # Copyright (c) 2009, Willow Garage, Inc.
4 | # Copyright (c) 2017, wstool authors
5 | # All rights reserved.
6 | #
7 | # Redistribution and use in source and binary forms, with or without
8 | # modification, are permitted provided that the following conditions
9 | # are met:
10 | #
11 | # * Redistributions of source code must retain the above copyright
12 | # notice, this list of conditions and the following disclaimer.
13 | # * Redistributions in binary form must reproduce the above
14 | # copyright notice, this list of conditions and the following
15 | # disclaimer in the documentation and/or other materials provided
16 | # with the distribution.
17 | # * Neither the name of Willow Garage, Inc. nor the names of its
18 | # contributors may be used to endorse or promote products derived
19 | # from this software without specific prior written permission.
20 | #
21 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 | # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 | # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24 | # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25 | # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26 | # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 | # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 | # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29 | # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 | # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31 | # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32 | # POSSIBILITY OF SUCH DAMAGE.
33 |
34 | import os
35 | import subprocess
36 |
37 | from wstool.wstool_cli import wstool_main
38 |
39 | from test.scm_test_base import AbstractSCMTest, _add_to_file
40 |
41 |
42 | def create_git_repo(remote_path):
43 | # create a "remote" repo
44 | subprocess.check_call(["git", "init"], cwd=remote_path)
45 | subprocess.check_call(["touch", "1.txt"], cwd=remote_path)
46 | subprocess.check_call(["git", "add", "."], cwd=remote_path)
47 | subprocess.check_call(["git", "commit", "-m", "first commit"], cwd=remote_path)
48 | subprocess.check_call(["touch", "2.txt"], cwd=remote_path)
49 | subprocess.check_call(["git", "add", "."], cwd=remote_path)
50 | subprocess.check_call(["git", "commit", "-m", "second commit"], cwd=remote_path)
51 | subprocess.check_call(["touch", "3.txt"], cwd=remote_path)
52 | subprocess.check_call(["git", "add", "."], cwd=remote_path)
53 | subprocess.check_call(["git", "commit", "-m", "third commit"], cwd=remote_path)
54 |
55 |
56 | class WstoolShallowCheckoutGitTest(AbstractSCMTest):
57 |
58 | @classmethod
59 | def setUpClass(self):
60 | AbstractSCMTest.setUpClass()
61 | remote_path = os.path.join(self.test_root_path, "remote")
62 | os.makedirs(remote_path)
63 |
64 | create_git_repo(remote_path)
65 |
66 | self.rosinstall_filename = os.path.join(self.local_path, "shallow-test.rosinstall")
67 | _add_to_file(self.rosinstall_filename, "- git: {local-name: clone, uri: \"file://" + remote_path + "\"}")
68 |
69 | cmd = ["wstool", "init", "ws-without-shallow", self.rosinstall_filename]
70 | os.chdir(self.test_root_path)
71 | wstool_main(cmd)
72 |
73 | cmd = ["wstool", "init", "--shallow", "ws-with-shallow", self.rosinstall_filename]
74 | os.chdir(self.test_root_path)
75 | wstool_main(cmd)
76 |
77 | def test_history_without_shallow(self):
78 | """Test history of cloned repo without shallow option"""
79 |
80 | clone_path = os.path.join(self.test_root_path, "ws-without-shallow", "clone")
81 |
82 | output = subprocess.check_output(["git", "log", "--pretty=format:%s"], cwd=clone_path)
83 | self.assertEqual(output.decode("ascii"), "third commit\nsecond commit\nfirst commit")
84 |
85 | def test_history_with_shallow(self):
86 | """Test history of cloned repo with shallow option"""
87 |
88 | clone_path = os.path.join(self.test_root_path, "ws-with-shallow", "clone")
89 |
90 | output = subprocess.check_output(["git", "log", "--pretty=format:%s"], cwd=clone_path)
91 | self.assertEqual(output.decode("ascii"), "third commit")
92 |
93 | def test_compare_workspace(self):
94 | """Compare worktrees with/without shallow option"""
95 |
96 | clone_path_without_shallow = os.path.join(self.test_root_path, "ws-without-shallow", "clone")
97 | clone_path_with_shallow = os.path.join(self.test_root_path, "ws-with-shallow", "clone")
98 |
99 | output = subprocess.check_output(["diff", "--exclude=.git", clone_path_without_shallow, clone_path_with_shallow], cwd=self.test_root_path)
100 | self.assertEqual(output.decode("ascii"), "")
101 |
--------------------------------------------------------------------------------
/test/local/test_tarfile.py:
--------------------------------------------------------------------------------
1 | import os
2 | import copy
3 | import yaml
4 |
5 | import wstool
6 | import wstool.helpers
7 | from wstool.wstool_cli import wstool_main
8 |
9 | from test.scm_test_base import AbstractFakeRosBasedTest, _create_yaml_file, _create_config_elt_dict, _create_tar_file
10 |
11 |
12 | class RosinstallTarTest(AbstractFakeRosBasedTest):
13 | """Tests for tarfile support"""
14 |
15 | @classmethod
16 | def setUpClass(self):
17 | AbstractFakeRosBasedTest.setUpClass()
18 |
19 | # create another repo in git
20 |
21 | self.tar_path = os.path.join(self.test_root_path, "tarfile.tar.bz2")
22 | _create_tar_file(self.tar_path)
23 |
24 | self.simple_tar_rosinstall = os.path.join(self.test_root_path, "simple_changed_uri.rosinstall")
25 | # same local name for gitrepo, different uri
26 | _create_yaml_file([_create_config_elt_dict("tar", "temptar", uri=self.tar_path, version='temptar')],
27 | self.simple_tar_rosinstall)
28 |
29 | def test_install(self):
30 | cmd = copy.copy(self.wstool_fn)
31 | cmd.extend(["init", self.directory, self.simple_tar_rosinstall])
32 | self.assertEquals(0, wstool_main(cmd))
33 |
34 | self.assertTrue(os.path.isdir(os.path.join(self.directory, "temptar")))
35 | self.assertTrue(os.path.isfile(os.path.join(self.directory, ".rosinstall")))
36 | stream = open(os.path.join(self.directory, '.rosinstall'), 'r')
37 | yamlsrc = yaml.safe_load(stream)
38 | stream.close()
39 | self.assertEqual(1, len(yamlsrc))
40 | self.assertEqual('tar', list(yamlsrc[0].keys())[0])
41 |
--------------------------------------------------------------------------------
/test/scm_test_base.py:
--------------------------------------------------------------------------------
1 | # Software License Agreement (BSD License)
2 | #
3 | # Copyright (c) 2009, Willow Garage, Inc.
4 | # All rights reserved.
5 | #
6 | # Redistribution and use in source and binary forms, with or without
7 | # modification, are permitted provided that the following conditions
8 | # are met:
9 | #
10 | # * Redistributions of source code must retain the above copyright
11 | # notice, this list of conditions and the following disclaimer.
12 | # * Redistributions in binary form must reproduce the above
13 | # copyright notice, this list of conditions and the following
14 | # disclaimer in the documentation and/or other materials provided
15 | # with the distribution.
16 | # * Neither the name of Willow Garage, Inc. nor the names of its
17 | # contributors may be used to endorse or promote products derived
18 | # from this software without specific prior written permission.
19 | #
20 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 | # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 | # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 | # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 | # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 | # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 | # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 | # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 | # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 | # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 | # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 | # POSSIBILITY OF SUCH DAMAGE.
32 |
33 | from __future__ import unicode_literals
34 |
35 | import os
36 | import copy
37 | import unittest
38 | import subprocess
39 | import tempfile
40 | import shutil
41 |
42 |
43 | def _add_to_file(path, content):
44 | """Util function to append to file to get a modification"""
45 | with open(path, 'ab') as fhand:
46 | fhand.write(content.encode('UTF-8'))
47 |
48 |
49 | def _create_fake_ros_dir(root_path):
50 | """setup fake ros root within root_path/ros"""
51 | ros_path = os.path.join(root_path, "ros")
52 | os.makedirs(ros_path)
53 | bin_path = os.path.join(ros_path, "bin")
54 | os.makedirs(bin_path)
55 | subprocess.check_call(["git", "init"], cwd=ros_path)
56 | _add_to_file(os.path.join(ros_path, "stack.xml"), '')
57 | _add_to_file(os.path.join(ros_path, "setup.sh"), 'export FOO_BAR=`pwd`')
58 | _add_to_file(os.path.join(bin_path, "rosmake"), '#!/usr/bin/env sh')
59 | _add_to_file(os.path.join(bin_path, "rospack"), '#!/usr/bin/env sh')
60 | # even faking rosmake
61 | subprocess.check_call(["chmod", "u+x", os.path.join(bin_path, "rosmake")])
62 | subprocess.check_call(["chmod", "u+x", os.path.join(bin_path, "rospack")])
63 | subprocess.check_call(["git", "add", "*"], cwd=ros_path)
64 | subprocess.check_call(["git", "commit", "-m", "initial"], cwd=ros_path)
65 |
66 |
67 | def _create_yaml_file(config_elements, path):
68 | content = ''
69 | for elt in list(config_elements):
70 | content += "- %s:\n" % elt["type"]
71 | if elt["uri"] is not None:
72 | content += " uri: '%s'\n" % elt["uri"]
73 | content += " local-name: '%s'\n" % elt["local-name"]
74 | if elt["version"] is not None:
75 | content += " version: '%s'\n" % elt["version"]
76 | _add_to_file(path, content)
77 |
78 |
79 | def _create_config_elt_dict(scmtype, localname, uri=None, version=None):
80 | element = {}
81 | element["type"] = scmtype
82 | element["uri"] = uri
83 | element["local-name"] = localname
84 | element["version"] = version
85 | return element
86 |
87 |
88 | def _create_git_repo(git_path):
89 | os.makedirs(git_path)
90 | subprocess.check_call(["git", "init"], cwd=git_path)
91 | subprocess.check_call(["touch", "gitfixed.txt"], cwd=git_path)
92 | subprocess.check_call(["git", "add", "*"], cwd=git_path)
93 | subprocess.check_call(["git", "commit", "-m", "initial"], cwd=git_path)
94 |
95 |
96 | def _create_tar_file(tar_file):
97 | parent_path = os.path.dirname(tar_file)
98 | tar_path = os.path.join(parent_path, 'temptar')
99 | os.makedirs(tar_path)
100 | subprocess.check_call(["touch", "tarfixed.txt"], cwd=tar_path)
101 | subprocess.check_call(["tar", "-czf", os.path.basename(tar_file), 'temptar'], cwd=parent_path)
102 |
103 |
104 | def _create_hg_repo(hg_path):
105 | os.makedirs(hg_path)
106 | subprocess.check_call(["hg", "init"], cwd=hg_path)
107 | subprocess.check_call(["touch", "hgfixed.txt"], cwd=hg_path)
108 | subprocess.check_call(["hg", "add", "hgfixed.txt"], cwd=hg_path)
109 | subprocess.check_call(["hg", "commit", "-m", "initial"], cwd=hg_path)
110 |
111 |
112 | def _nth_line_split(n, output):
113 | """returns the last line as list of non-blank tokens"""
114 | lines = output.splitlines()
115 | if len(lines) > 0:
116 | return lines[n].split()
117 | else:
118 | return []
119 |
120 |
121 | def get_git_hash(git_path):
122 | po = subprocess.Popen(["git", "rev-parse", "HEAD"], cwd=git_path,
123 | stdout=subprocess.PIPE)
124 | return po.stdout.read().decode('UTF-8').rstrip('"\n').lstrip('"\n')
125 |
126 |
127 | # ROSINSTALL_CMD = os.path.join(os.getcwd(), 'scripts/rosinstall')
128 | # ROSWS_CMD = os.path.join(os.getcwd(), 'scripts/rosws')
129 |
130 |
131 | class AbstractRosinstallCLITest(unittest.TestCase):
132 |
133 | """Base class for cli tests"""
134 | @classmethod
135 | def setUpClass(self):
136 | os.environ['GIT_AUTHOR_NAME'] = 'Your Name'
137 | os.environ['GIT_COMMITTER_NAME'] = 'Your Name'
138 | os.environ['GIT_AUTHOR_EMAIL'] = 'name@example.com'
139 | os.environ['EMAIL'] = 'Your Name '
140 | self.new_environ = copy.copy(os.environ)
141 | self.new_environ["PYTHONPATH"] = os.path.join(os.getcwd(), "src")
142 | if "ROS_WORKSPACE" in self.new_environ:
143 | self.new_environ.pop("ROS_WORKSPACE")
144 |
145 |
146 | class AbstractRosinstallBaseDirTest(AbstractRosinstallCLITest):
147 | """test class where each test method get its own fresh tempdir named self.directory"""
148 |
149 | def setUp(self):
150 | self.directories = {}
151 | self.directory = tempfile.mkdtemp()
152 | self.directories["base"] = self.directory
153 | self.wstool_fn = ["wstool"]
154 |
155 | def tearDown(self):
156 | for d in self.directories:
157 | shutil.rmtree(self.directories[d])
158 | self.directories = {}
159 |
160 |
161 | class AbstractFakeRosBasedTest(AbstractRosinstallBaseDirTest):
162 | """
163 | creates some larger infrastructure for testing locally:
164 | a root folder containing all other folders in self.test_root_path
165 | a fake ros folder in self.ros_path
166 | a git repo in self.git_path
167 | a hg repo in self.hg_path
168 | a file named self.simple_rosinstall with ros and gitrepo
169 | a file named self.simple_changed_vcs_rosinstall with ros and hgrepo
170 | """
171 |
172 | @classmethod
173 | def setUpClass(self):
174 | AbstractRosinstallBaseDirTest.setUpClass()
175 | # create a dir mimicking ros
176 | self.test_root_path = os.path.realpath(tempfile.mkdtemp())
177 | _create_fake_ros_dir(self.test_root_path)
178 | # create a repo in git
179 | self.ros_path = os.path.join(self.test_root_path, "ros")
180 | self.git_path = os.path.join(self.test_root_path, "gitrepo")
181 | _create_git_repo(self.git_path)
182 | # create a repo in hg
183 | self.hg_path = os.path.join(self.test_root_path, "hgrepo")
184 | _create_hg_repo(self.hg_path)
185 | # create custom wstool files to use as input
186 | self.simple_rosinstall = os.path.join(self.test_root_path, "simple.rosinstall")
187 | _create_yaml_file([_create_config_elt_dict("git", "ros", self.ros_path),
188 | _create_config_elt_dict("git", "gitrepo", self.git_path)],
189 | self.simple_rosinstall)
190 | self.simple_changed_vcs_rosinstall = os.path.join(self.test_root_path, "simple_changed_vcs.rosinstall")
191 | _create_yaml_file([_create_config_elt_dict("git", "ros", self.ros_path),
192 | _create_config_elt_dict("hg", "hgrepo", self.hg_path)],
193 | self.simple_changed_vcs_rosinstall)
194 |
195 | @classmethod
196 | def tearDownClass(self):
197 | shutil.rmtree(self.test_root_path)
198 |
199 |
200 | class AbstractSCMTest(AbstractRosinstallCLITest):
201 | """Base class for diff tests, setting up a tempdir self.test_root_path for a whole class"""
202 | @classmethod
203 | def setUpClass(self):
204 | """creates a directory 'ros' mimicking to be a ROS root to rosinstall"""
205 | AbstractRosinstallCLITest.setUpClass()
206 | self.test_root_path = os.path.realpath(tempfile.mkdtemp())
207 | self.directories = {}
208 | self.directories["root"] = self.test_root_path
209 |
210 | _create_fake_ros_dir(self.test_root_path)
211 | self.local_path = os.path.join(self.test_root_path, "ws")
212 | os.makedirs(self.local_path)
213 | self.curdir = os.getcwd()
214 |
215 | @classmethod
216 | def tearDownClass(self):
217 | os.chdir(self.curdir)
218 | for d in self.directories:
219 | shutil.rmtree(self.directories[d])
220 |
221 | def assertStatusListEqual(self, listexpect, listactual):
222 | """helper fun to check scm status output while discarding file ordering differences"""
223 | lines_expect = listexpect.splitlines()
224 | lines_actual = listactual.splitlines()
225 | for line in lines_expect:
226 | self.assertTrue(line in lines_actual, 'Missing entry %s in output %s' % (line, listactual))
227 | for line in lines_actual:
228 | self.assertTrue(line in lines_expect, 'Superflous entry %s in output %s' % (line, listactual))
229 |
230 |
231 | class UtilTest(unittest.TestCase):
232 | """test to check the methods run by unit test setups"""
233 |
234 | def test_add_to_file(self):
235 | self.test_root_path = tempfile.mkdtemp()
236 | filepath = os.path.join(self.test_root_path, 'foofile')
237 | self.assertFalse(os.path.exists(filepath))
238 | _add_to_file(filepath, 'foo')
239 | self.assertTrue(os.path.exists(filepath))
240 | with open(filepath, 'r') as f:
241 | read_data = f.read()
242 | self.assertEqual(read_data, 'foo')
243 | _add_to_file(filepath, 'bar')
244 | with open(filepath, 'r') as f:
245 | read_data = f.read()
246 | self.assertEqual(read_data, 'foobar')
247 | shutil.rmtree(self.test_root_path)
248 |
249 | def test_create_fake_ros(self):
250 | self.test_root_path = tempfile.mkdtemp()
251 | rospath = os.path.join(self.test_root_path, 'ros')
252 | self.assertFalse(os.path.exists(rospath))
253 | _create_fake_ros_dir(self.test_root_path)
254 | self.assertTrue(os.path.exists(rospath))
255 | self.assertTrue(os.path.exists(os.path.join(rospath, "setup.sh")))
256 | self.assertTrue(os.path.exists(os.path.join(rospath, "stack.xml")))
257 | self.assertTrue(os.path.exists(os.path.join(rospath, ".git")))
258 | shutil.rmtree(self.test_root_path)
259 |
260 | def test_create_config_elt_dict(self):
261 | scmtype = 'foo'
262 | uri = 'bar'
263 | localname = 'pip'
264 | version = 'pop'
265 | element = _create_config_elt_dict(scmtype, localname, uri, version)
266 | self.assertEqual(element["type"], scmtype)
267 | self.assertEqual(element["uri"], uri)
268 | self.assertEqual(element["local-name"], localname)
269 | self.assertEqual(element["version"], version)
270 |
271 | def test_create_yaml_file(self):
272 | self.test_root_path = tempfile.mkdtemp()
273 | filepath = os.path.join(self.test_root_path, 'foofile')
274 | config_elements = [
275 | _create_config_elt_dict("other", "foo"),
276 | _create_config_elt_dict("git", "foo", "foouri"),
277 | _create_config_elt_dict("svn", "bar", "baruri", "barversion")]
278 | _create_yaml_file(config_elements, filepath)
279 | with open(filepath, 'r') as f:
280 | read_data = f.read()
281 | self.assertEqual(read_data, """- other:
282 | local-name: 'foo'
283 | - git:
284 | uri: 'foouri'
285 | local-name: 'foo'
286 | - svn:
287 | uri: 'baruri'
288 | local-name: 'bar'
289 | version: 'barversion'
290 | """)
291 | shutil.rmtree(self.test_root_path)
292 |
--------------------------------------------------------------------------------
/tox.ini:
--------------------------------------------------------------------------------
1 | # Tox is the QA gateway before releasing
2 | # it can run against multiple python versions
3 | # it runs commands in virtualenvs prepared with python version and dependencies from setup.[py,cfg]
4 | # While tox can be configured to do plenty of things, it is bothersome to work with quickly, and it is not a lightweight dependency, so prefer to write build logic in setup.py or other commands that run without tox.
5 |
6 | [tox]
7 | envlist = py27, py34, py35, py36
8 |
9 | [testenv]
10 | # flawed due to https://github.com/tox-dev/tox/issues/149
11 | # deps = -rrequirements.txt
12 |
13 | commands =
14 | pip install .[test]
15 | {envpython} setup.py test
16 | py36: {envpython} setup.py sdist bdist_wheel
17 |
--------------------------------------------------------------------------------