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# Author: kwc 35 36""" 37Library for locating ROS packages and stacks using the centralized 38index at ROS.org. 39""" 40 41from __future__ import print_function 42 43NAME = 'roslocate' 44 45import os 46import sys 47try: 48 from os import EX_USAGE 49except ImportError: 50 EX_USAGE = 0, 1, 2 51 52from optparse import OptionParser 53from rosinstall.locate import get_manifest, \ 54 get_www, get_repo, get_vcs, get_vcs_uri_for_branch,\ 55 get_rosinstall, InvalidData, BRANCH_RELEASE, BRANCH_DEVEL 56 57 58def options_to_branch(options): 59 # we don't let the user express the full range of options at the 60 # command-line, mainly for (1) simplicity and (2) the distro 61 # branch is not reliable. 62 if options.dev and options.rel: 63 sys.exit('only one of --dev and --rel can be used') 64 if options.dev: 65 return BRANCH_DEVEL 66 elif options.rel: 67 return BRANCH_RELEASE 68 return None 69 70def cmd_get_rosinstall(name, data, type_, options=None): 71 branch = options_to_branch(options) 72 prefix = options.prefix if options is not None and options.prefix else '' 73 return get_rosinstall(name, data, type_, branch, prefix) 74 75 76def get_type(name, data, type_, options=None): 77 return type_ 78 79 80def cmd_get_vcs_uri(name, data, type_, options=None): 81 return get_vcs_uri_for_branch(data, options_to_branch(options)) 82 83 84def cmd_get_vcs(name, data, type_, options=None): 85 return get_vcs(name, data, type_) 86 87 88def cmd_get_www(name, data, type_, options=None): 89 return get_www(name, data, type_) 90 91 92def get_description(name, data, type_, options=None): 93 if type_ == 'package': 94 return """ 95Type: package 96Stack: %s 97Description: %s 98URL: %s 99 """ % (data.get('stack', 'none'), data.get('description', ''), data.get('url', '')) 100 elif type_ == 'stack': 101 return """ 102Type: package 103Stack: %s 104Description: %s 105URL: %s 106 """ % (data.get('stack', 'none'), data.get('description', ''), data.get('url', '')) 107 else: 108 return """ 109Type: %s 110Packages: %s 111Description: %s 112URL: %s 113 """ % (type_, ", ".join(data.get('packages', [])), data.get('description', ''), data.get('url', '')) 114 115 116def cmd_get_repo(name, data, type_, options=None): 117 return get_repo(name, data, type_) 118 119################################################################################ 120 121# Bind library to commandline implementation 122 123 124def _fullusage(parser, error=EX_USAGE): 125 parser.print_help(file=sys.stderr) 126 sys.stderr.write(""" 127Commands: 128 info\t\tGet rosinstall info of resource 129 vcs\t\tGet name of source control system 130 type\t\tPackage or stack 131 uri\t\tGet source control URI of resource 132 www\t\tGet web page of resource 133 repo\t\tGet repository name of resource 134 describe\tGet description of resource 135""") 136 sys.exit(error) 137 138_cmds = { 139 # info/rosinstall are now identical 140 'info': cmd_get_rosinstall, 141 'rosinstall': cmd_get_rosinstall, #alias 142 'vcs': cmd_get_vcs, 143 'type': get_type, 144 'uri': cmd_get_vcs_uri, 145 'repo': cmd_get_repo, 146 'www': cmd_get_www, 147 'describe': get_description, 148 'description': get_description, # alias 149 } 150 151 152def roslocate_main(): 153 args = sys.argv 154 155 parser = OptionParser(usage="usage: %prog <command> <resource> <options>", prog=NAME) 156 157 parser.add_option("--prefix", 158 dest="prefix", default=False, 159 metavar="PATH", 160 help="path prefix for rosinstall") 161 162 # TODO: distro-specific return values 163 parser.add_option("--distro", 164 dest="distro", 165 help="fetch information for specific ROS distribution release (default: environment variable ROS_DISTRO if defined)") 166 167 # In this implementation, we're optimizing for the use case where 168 # the user wishes to do a source-based install of a released 169 # stack. The user also has an efficient flag for specifying that 170 # they want a development branch instead. We are not exposing 171 # users to the full range of devel/released/distro branches that 172 # the rosinstall file encodes, mainly because the distro branch is 173 # not reliable with DVCS systems like git. Thus, rosinstall 174 # abstracts the logic for determining what the correct released 175 # branch to use is. 176 parser.add_option("--dev", 177 dest="dev", default=False, 178 action="store_true", 179 help="fetch development branch information") 180 parser.add_option("--rel", 181 dest="rel", default=False, 182 action="store_true", 183 help="fetch release branch information") 184 185 # parse command 186 if '-h' in args or '--help' in args: 187 # printing commands in OptionParser is a mess 188 _fullusage(parser, error=0) 189 if len(args) < 2: 190 _fullusage(parser) 191 192 # noop parse for now. Will matter once we can pass in --distro 193 options, args = parser.parse_args() 194 195 cmd = args[0] 196 if not cmd in _cmds.keys(): 197 _fullusage(parser) 198 199 if cmd not in ['info', 'rosinstall'] and options.prefix: 200 parser.error('--prefix only allowed with commands info, rosinstall') 201 202 203 if len(args) != 2: 204 parser.error("please provide a resource name (package or stack)") 205 name = args[1] 206 207 if not options.distro: 208 distro = os.environ['ROS_DISTRO'] if 'ROS_DISTRO' in os.environ else None 209 if distro: 210 print('Using ROS_DISTRO: %s' % distro, file=sys.stderr) 211 options.distro = distro 212 else: 213 parser.error("please provide the distro name with --distro DISTRO_NAME") 214 215 try: 216 data, type_, _ = get_manifest(name, options.distro) 217 except IOError: 218 sys.exit('cannot locate information about %s\n' % (name)) 219 220 try: 221 print (_cmds[cmd](name, data, type_, options)) 222 sys.stdout.flush() # raises correct error when used in a pipe 223 except InvalidData as e: 224 sys.stderr.write("%s\n" % e) 225 except IOError as ioe: 226 if ioe.errno == 32: 227 sys.exit(ioe) 228 raise 229 230if __name__ == '__main__': 231 roslocate_main() 232