<commit_before># Software License Agreement (BSD License)
#
# Copyright (c) 2008, <NAME>, Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
#  * Redistributions of source code must retain the above copyright
#    notice, this list of conditions and the following disclaimer.
#  * Redistributions in binary form must reproduce the above
#    copyright notice, this list of conditions and the following
#    disclaimer in the documentation and/or other materials provided
#    with the distribution.
#  * Neither the name of <NAME>, Inc. nor the names of its
#    contributors may be used to endorse or promote products derived
#    from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
# Revision $Id$
# $Author$

import os
import sys
import stat
import string

from subprocess import Popen, PIPE

import roslib.exceptions
import roslib.names
import roslib.rosenv

MSG_DIR = 'msg'
SRV_DIR = 'srv'
SRC_DIR = 'src'

# aliases
ROS_PACKAGE_PATH = roslib.rosenv.ROS_PACKAGE_PATH
ROS_ROOT = roslib.rosenv.ROS_ROOT

class ROSPkgException(roslib.exceptions.ROSLibException):
    """
    Base class of package-related errors.
    """
    pass
class InvalidROSPkgException(ROSPkgException):
    """
    Exception that indicates that a ROS package does not exist
    """
    pass
class MultipleNodesException(ROSPkgException):
    """
    Exception that indicates that multiple ROS nodes by the same name are in the same package.
    """
    pass

# TODO: go through the code and eliminate unused methods -- there's far too many combos here

MANIFEST_FILE = 'manifest.xml'

#
# Map package/directory structure
#

def is_pkg_dir(d):
    """
    @param d: directory location
    @type  d: str
    @return: True if d is the root directory of a ROS Package
    @rtype: bool
    """
    return os.path.isfile(os.path.join(d, MANIFEST_FILE))

def get_package_paths(ros_root_required=True, env=None):
    """
    Get the paths to search for packages
    
    @param ros_root_required: if True, raise exception if
    environment is invalid (i.e. ROS_ROOT is not set properly)
    @type  ros_root_required: bool
    @param env: override os.environ dictionary
    @type  env: dict
    @raise roslib.rosenv.ROSEnvException: if ros_root_required is True
    and ROS_ROOT is not set
    """
    if env is None:
        env = os.environ
    rpp = roslib.rosenv.get_ros_package_path(required=False, env=env)
    if rpp:
        paths = [x for x in rpp.split(os.pathsep) if x]
    else:
        paths = []
    rr_path = roslib.rosenv.get_ros_root(required=ros_root_required, env=env)
    if rr_path:
        return paths + [rr_path]
    else:
        return paths

def get_dir_pkg(d):
    """
    Get the package that the directory is contained within. This is
    determined by finding the nearest parent manifest.xml file. This
    isn't 100% reliable, but symlinks can full any heuristic that
    relies on ROS_ROOT.
    @param d: directory path
    @type  d: str
    @return: (package_directory, package) of the specified directory, or None,None if not in a package
    @rtype: (str, str)
    """
    #TODO: the realpath is going to create issues with symlinks, most likely

    parent = os.path.dirname(os.path.realpath(d))
    #walk up until we hit ros root or ros/pkg
    while not os.path.exists(os.path.join(d, MANIFEST_FILE)) and parent != d:
        d = parent
        parent = os.path.dirname(d)
    if os.path.exists(os.path.join(d, MANIFEST_FILE)):
        pkg = os.path.basename(os.path.abspath(d))
        return d, pkg
    return None, None

_pkg_dir_cache = {}

def get_pkg_dir(package, required=True, ros_root=None, ros_package_path=None):
    """
    Locate directory package is stored in
    
    @param package: package name
    @type  package: str
    @param required: if True, an exception will be raised if the
    package directory cannot be located.
    @type  required: bool
    @param ros_root: if specified, override ROS_ROOT
    @type  ros_root: str
    @param ros_package_path: if specified, override ROS_PACKAGE_PATH
    @type  ros_package_path: str
    @return: directory containing package or None if package cannot be found and required is False.
    @rtype: str
    @raise InvalidROSPkgException: if required is True and package cannot be located
    """    

    #UNIXONLY
    #TODO: replace with non-rospack-based solution (e.g. os.walk())
    try:
        penv = os.environ.copy()
        if ros_root:
            ros_root = roslib.rosenv.resolve_path(ros_root)
            rospack = os.path.join(ros_root, 'bin', 'rospack')
            penv[ROS_ROOT] = ros_root
        else:
            rospack = 'rospack'
            # record setting for _pkg_dir_cache
            if ROS_ROOT in os.environ:
                ros_root = os.environ[ROS_ROOT]
        if ros_package_path is not None:
            ros_package_path = roslib.rosenv.resolve_paths(ros_package_path)
            penv[ROS_PACKAGE_PATH] = ros_package_path
        elif ROS_PACKAGE_PATH in os.environ:
            # record setting for _pkg_dir_cache
            ros_package_path = os.environ[ROS_PACKAGE_PATH]

        # now that we've resolved the args, check the cache
        if package in _pkg_dir_cache:
            dir, rr, rpp = _pkg_dir_cache[package]<commit_msg>roslib.get_pkg_dir: #2144 always invoke rospack with full path when its possible to derive it so that it works on remote machines<commit_after># Software License Agreement (BSD License)
#
# Copyright (c) 2008, <NAME>, Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
#  * Redistributions of source code must retain the above copyright
#    notice, this list of conditions and the following disclaimer.
#  * Redistributions in binary form must reproduce the above
#    copyright notice, this list of conditions and the following
#    disclaimer in the documentation and/or other materials provided
#    with the distribution.
#  * Neither the name of <NAME>, Inc. nor the names of its
#    contributors may be used to endorse or promote products derived
#    from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
# Revision $Id$
# $Author$

import os
import sys
import stat
import string

from subprocess import Popen, PIPE

import roslib.exceptions
import roslib.names
import roslib.rosenv

MSG_DIR = 'msg'
SRV_DIR = 'srv'
SRC_DIR = 'src'

# aliases
ROS_PACKAGE_PATH = roslib.rosenv.ROS_PACKAGE_PATH
ROS_ROOT = roslib.rosenv.ROS_ROOT

class ROSPkgException(roslib.exceptions.ROSLibException):
    """
    Base class of package-related errors.
    """
    pass
class InvalidROSPkgException(ROSPkgException):
    """
    Exception that indicates that a ROS package does not exist
    """
    pass
class MultipleNodesException(ROSPkgException):
    """
    Exception that indicates that multiple ROS nodes by the same name are in the same package.
    """
    pass

# TODO: go through the code and eliminate unused methods -- there's far too many combos here

MANIFEST_FILE = 'manifest.xml'

#
# Map package/directory structure
#

def is_pkg_dir(d):
    """
    @param d: directory location
    @type  d: str
    @return: True if d is the root directory of a ROS Package
    @rtype: bool
    """
    return os.path.isfile(os.path.join(d, MANIFEST_FILE))

def get_package_paths(ros_root_required=True, env=None):
    """
    Get the paths to search for packages
    
    @param ros_root_required: if True, raise exception if
    environment is invalid (i.e. ROS_ROOT is not set properly)
    @type  ros_root_required: bool
    @param env: override os.environ dictionary
    @type  env: dict
    @raise roslib.rosenv.ROSEnvException: if ros_root_required is True
    and ROS_ROOT is not set
    """
    if env is None:
        env = os.environ
    rpp = roslib.rosenv.get_ros_package_path(required=False, env=env)
    if rpp:
        paths = [x for x in rpp.split(os.pathsep) if x]
    else:
        paths = []
    rr_path = roslib.rosenv.get_ros_root(required=ros_root_required, env=env)
    if rr_path:
        return paths + [rr_path]
    else:
        return paths

def get_dir_pkg(d):
    """
    Get the package that the directory is contained within. This is
    determined by finding the nearest parent manifest.xml file. This
    isn't 100% reliable, but symlinks can full any heuristic that
    relies on ROS_ROOT.
    @param d: directory path
    @type  d: str
    @return: (package_directory, package) of the specified directory, or None,None if not in a package
    @rtype: (str, str)
    """
    #TODO: the realpath is going to create issues with symlinks, most likely

    parent = os.path.dirname(os.path.realpath(d))
    #walk up until we hit ros root or ros/pkg
    while not os.path.exists(os.path.join(d, MANIFEST_FILE)) and parent != d:
        d = parent
        parent = os.path.dirname(d)
    if os.path.exists(os.path.join(d, MANIFEST_FILE)):
        pkg = os.path.basename(os.path.abspath(d))
        return d, pkg
    return None, None

_pkg_dir_cache = {}

def get_pkg_dir(package, required=True, ros_root=None, ros_package_path=None):
    """
    Locate directory package is stored in
    
    @param package: package name
    @type  package: str
    @param required: if True, an exception will be raised if the
    package directory cannot be located.
    @type  required: bool
    @param ros_root: if specified, override ROS_ROOT
    @type  ros_root: str
    @param ros_package_path: if specified, override ROS_PACKAGE_PATH
    @type  ros_package_path: str
    @return: directory containing package or None if package cannot be found and required is False.
    @rtype: str
    @raise InvalidROSPkgException: if required is True and package cannot be located
    """    

    #UNIXONLY
    #TODO: replace with non-rospack-based solution (e.g. os.walk())
    try:
        penv = os.environ.copy()
        if ros_root:
            ros_root = roslib.rosenv.resolve_path(ros_root)
            penv[ROS_ROOT] = ros_root
        elif ROS_ROOT in os.environ:
            # record setting for _pkg_dir_cache
            ros_root = os.environ[ROS_ROOT]
        if ros_root:
            rospack = os.path.join(ros_root, 'bin', 'rospack')
        else:
            rospack = 'rospack'
        if ros_package_path is not None:
            ros_package_path = roslib.rosenv.resolve_paths(ros_package_path)
            penv[ROS_PACKAGE_PATH] = ros_package_path
        elif ROS_PACKAGE_PATH in os.environ:
            # record setting for _pkg_dir_cache
            ros_package_path = os.environ[ROS_PACKAGE_PATH]

        # now that we've resolved the args, check the cache
        if package in _pkg_dir_cache:
            dir, rr, rpp = _pkg_dir_cache[package]
{'fraction_non_alphanumeric': 0.0731883476446513, 'fraction_numerical': 0.0014445068614075917, 'mean_word_length': 3.2044534412955468, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 7, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 4}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5430357', 'n_tokens_mistral': 3870, 'n_tokens_neox': 3689, 'n_words': 1393}