$search
00001 # Software License Agreement (BSD License) 00002 # 00003 # Copyright (c) 2010, Willow Garage, Inc. 00004 # All rights reserved. 00005 # 00006 # Redistribution and use in source and binary forms, with or without 00007 # modification, are permitted provided that the following conditions 00008 # are met: 00009 # 00010 # * Redistributions of source code must retain the above copyright 00011 # notice, this list of conditions and the following disclaimer. 00012 # * Redistributions in binary form must reproduce the above 00013 # copyright notice, this list of conditions and the following 00014 # disclaimer in the documentation and/or other materials provided 00015 # with the distribution. 00016 # * Neither the name of Willow Garage, Inc. nor the names of its 00017 # contributors may be used to endorse or promote products derived 00018 # from this software without specific prior written permission. 00019 # 00020 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 00021 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 00022 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 00023 # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 00024 # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 00025 # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 00026 # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 00027 # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 00028 # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 00029 # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 00030 # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 00031 # POSSIBILITY OF SUCH DAMAGE. 00032 # 00033 # Revision $Id: core.py 16578 2012-03-26 17:58:13Z kwc $ 00034 00035 import os 00036 import sys 00037 import yaml 00038 00039 import rospkg 00040 from rospkg.distro import DistroStack 00041 00042 def load_distro_index(filename): 00043 """ 00044 Load the distro index file, which is necessary for stacks that are installed in 00045 binary form instead of with the extra rosinstall meta fields 00046 """ 00047 with open(filename, 'r') as f: 00048 return yaml.load(f) 00049 00050 def repo_stacks(repo, checkout_dir): 00051 if repo.is_released_stack: 00052 # distro/debian install logic: repo is a released stack, no 00053 # need to crawl 00054 return [repo.name] 00055 else: 00056 # rosinstall logic 00057 repo_dir = os.path.join(checkout_dir, repo.local_path) 00058 if not os.path.exists(repo_dir): 00059 sys.stderr.write("checkout [%s] doesn't exist\n"%(repo_dir)) 00060 return [] 00061 00062 stacks = rospkg.list_by_path('stack.xml', repo_dir, {}) 00063 if repo.name == 'ros': 00064 stacks.append('ros') 00065 return stacks 00066 00067 def repo_packages(repo, checkout_dir): 00068 rosstack = rospkg.RosStack() 00069 if repo.is_released_stack: 00070 # distro/debian install logic: repo is a released stack, no 00071 # need to crawl 00072 try: 00073 packages = rosstack.packages_of(repo.name) 00074 except: 00075 packages = [] 00076 else: 00077 # rosinstall logic 00078 repo_dir = os.path.join(checkout_dir, repo.local_path) 00079 packages = rospkg.list_by_path('manifest.xml', repo_dir, {}) 00080 return packages 00081 00082 def load_repos_distro(distro_index_filename): 00083 """ 00084 Load repository index for stacks that were installed via the 00085 distribution/debian. We have to fake repository data for these as 00086 we are not actually retrieving from the repository itself. 00087 """ 00088 repos = [] 00089 00090 # for released stacks, we use the metarepos logic to represent the 00091 # stack as its own repository as well as part of an aggregate 00092 # repository. 00093 distro_index = load_distro_index(distro_index_filename) 00094 distro_name = distro_index['distro_name'] 00095 for stack_name in distro_index['stacks']: 00096 stack_data= distro_index['stacks'][stack_name] 00097 00098 # should not be used (hopefully) 00099 if stack_name == 'ros': 00100 local_path = '/opt/ros/%s/ros'%(distro_name) 00101 else: 00102 local_path = '/opt/ros/%s/stacks/%s'%(distro_name, stack_name) 00103 00104 distro_stack = DistroStack(stack_name, stack_data['version'], 00105 distro_name, stack_data['rules']) 00106 00107 # use the release branch as that is what we are documenting 00108 # TODO: broken for bzr 00109 rosinstalls = {} 00110 vcs_config = distro_stack.vcs_config 00111 for branch_name in ['release', 'devel', 'distro']: 00112 rosinstalls[branch_name] = vcs_config.to_rosinstall(stack_name, branch_name, anonymous=True)[0] 00113 rosinstall = rosinstalls['release'] # default rosinstall 00114 00115 # for each debian-based stack, give it its own repo, plus an aggregate 00116 vcs_type = rosinstall.keys()[0] 00117 vcs_uri = rosinstall[vcs_type]['uri'] 00118 00119 print "loaded released stack repo: %s %s %s"%(stack_name, vcs_type, vcs_uri) 00120 print "released stack repo rosinstall: %s \n%s"%(stack_name, rosinstall) 00121 00122 r = Repo(stack_name, vcs_type, vcs_uri, rosinstall, local_path) 00123 r.aggregate_name = stack_data['repo'] 00124 r.is_released_stack = True 00125 r.rosinstalls = rosinstalls.copy() 00126 00127 repos.append((stack_name, r)) 00128 return repos 00129 00130 def load_repos(repos_filename, distro_index_filename): 00131 repos = load_repos_rosinstall(repos_filename) 00132 if distro_index_filename is not None: 00133 repos.extend(load_repos_distro(distro_index_filename)) 00134 return repos 00135 00136 def load_repos_rosinstall(filename): 00137 """ 00138 Load repository file, which is a rosinstall file with particular semantics 00139 00140 @return: ordered list of repositories 00141 @rtype: [(str, Repo)] 00142 """ 00143 with open(filename) as f: 00144 data = yaml.load(f.read()) 00145 # rosinstall file is a list of dictionaries 00146 repos = [] 00147 # have to reverse the repo order to match rosinstall precedence 00148 for d in reversed(data): 00149 type_ = d.keys()[0] 00150 if type_ == 'other': 00151 continue 00152 config = d[type_] 00153 # filter 'other' like elements that don't bear VCS info 00154 if not 'uri' in config: 00155 continue 00156 00157 local_name = local_path = config['local-name'] 00158 r = Repo(local_name, type_, config['uri'], d, local_path) 00159 if 'meta' in config and 'repo-name' in config['meta']: 00160 r.aggregate_name = config['meta']['repo-name'] 00161 repos.append((local_name, r)) 00162 return repos 00163 00164 class Repo(object): 00165 00166 def __init__(self, name, type_, uri, rosinstall, local_path): 00167 """ 00168 @param name: repository name 00169 @param type_: repository VCS type 00170 @param uri: repository VCS uri 00171 @param rosinstall: default rosinstall dictionary configuration data 00172 @param local_path: checkout-relative path for repository 00173 @param aggregate_name: (optional) aggregate name if we are 00174 grouping several repositories under a single name. 00175 Defaults to name. 00176 """ 00177 self.name = name 00178 self.type = type_ 00179 self.uri = uri 00180 # rosinstall data 00181 self.rosinstall = rosinstall 00182 self.local_path = local_path 00183 00184 # aggregate is used to alias per-stack repositories to a 00185 # single name, e.g. ccny-ros-pkg 00186 self.aggregate_name = None 00187 self.is_released_stack = False 00188 00189 # dictionary of different rosinstall configurations of repo, 00190 # uses same keys as VcsConfig.to_rosinstall, 00191 # e.g. {'devel': rosinstall_dict, 'release': rosinstall_dict} 00192 self.rosinstalls = None 00193 00194 _api_url = "http://ros.org/doc/api/" 00195 def package_link(package): 00196 return _api_url + package + "/html/" 00197 def stack_link(stack): 00198 return _api_url + stack + "/html/" 00199 00200 def safe_encode(d): 00201 d_copy = d.copy() 00202 for k, v in d_copy.iteritems(): 00203 if isinstance(v, basestring): 00204 try: 00205 d[k] = v.encode("utf-8") 00206 except UnicodeDecodeError, e: 00207 print >> sys.stderr, "error: cannot encode value for key", k 00208 d[k] = '' 00209 elif type(v) == list: 00210 try: 00211 d[k] = [x.encode("utf-8") for x in v] 00212 except UnicodeDecodeError, e: 00213 print >> sys.stderr, "error: cannot encode value for key", k 00214 d[k] = [] 00215 return d 00216