diff options
author | hauptmech | 2013-01-17 13:03:34 +0100 |
---|---|---|
committer | Benjamin Chrétien | 2015-06-20 02:25:11 +0900 |
commit | 5c90be666022c1bdf8abffe316920b944851a9cd (patch) | |
tree | db3469845d3bdb7867543bd17a1b509cba1eca27 | |
download | aur-5c90be666022c1bdf8abffe316920b944851a9cd.tar.gz |
Squashed commits
-rw-r--r-- | .SRCINFO | 27 | ||||
-rw-r--r-- | PKGBUILD | 42 | ||||
-rw-r--r-- | PKGBUILD.rostemplate | 32 | ||||
-rwxr-xr-x | create-arch-ros-package-legacy.sh | 62 | ||||
-rwxr-xr-x | fix-python-scripts.sh | 17 | ||||
-rwxr-xr-x | generate-python-patch.sh | 20 | ||||
-rwxr-xr-x | generate_packages_makefile.py | 130 | ||||
-rwxr-xr-x | get_stack_dependencies.py | 55 | ||||
-rwxr-xr-x | import_catkin_packages.py | 353 | ||||
-rw-r--r-- | stack-install-tools.sh | 56 |
10 files changed, 794 insertions, 0 deletions
diff --git a/.SRCINFO b/.SRCINFO new file mode 100644 index 000000000000..ab67b5c27caf --- /dev/null +++ b/.SRCINFO @@ -0,0 +1,27 @@ +pkgbase = ros-build-tools + pkgdesc = Utilities for building arch packages for ROS stacks. + pkgver = 0.0.1 + pkgrel = 3 + url = http://www.ros.org + arch = i686 + arch = x86_64 + license = BSD + source = fix-python-scripts.sh + source = stack-install-tools.sh + source = create-arch-ros-package-legacy.sh + source = PKGBUILD.rostemplate + source = get_stack_dependencies.py + source = generate_packages_makefile.py + source = generate-python-patch.sh + source = import_catkin_packages.py + md5sums = b2b4fd23abb8e9e7382ef9aeab2542f5 + md5sums = 79ae7fb600e116623a42631d15d66a87 + md5sums = ac82eca7efc9f0ff7e8b976a83692868 + md5sums = f3378832c3ba121f7c9e17dc43c8b1d4 + md5sums = d257f7f20384e894b0431ee61068aa96 + md5sums = 563c9d1320a3a997db25d3087303dcfb + md5sums = 8d6d7eb89a12c449497b209f1a06655b + md5sums = 85fc98bd9df02afa0d8a27c01db78c66 + +pkgname = ros-build-tools + diff --git a/PKGBUILD b/PKGBUILD new file mode 100644 index 000000000000..9e9addb1f47b --- /dev/null +++ b/PKGBUILD @@ -0,0 +1,42 @@ +# Maintainer: Sean Greenslade <zootboysean@gmail.com> + +pkgdesc='Utilities for building arch packages for ROS stacks.' +url=http://www.ros.org + +pkgname='ros-build-tools' +pkgver='0.0.1' +arch=('i686' 'x86_64') +pkgrel=3 +license=('BSD') +makedepends=() +depends=() + +pkg_destination_dir="/usr/share/ros-build-tools" + +source=('fix-python-scripts.sh' + 'stack-install-tools.sh' + 'create-arch-ros-package-legacy.sh' + 'PKGBUILD.rostemplate' + 'get_stack_dependencies.py' + 'generate_packages_makefile.py' + 'generate-python-patch.sh' + 'import_catkin_packages.py') + +build() { + return 0 +} +package() { + mkdir -p ${pkgdir}${pkg_destination_dir} + for file in "${source[@]}"; do + cp $file ${pkgdir}${pkg_destination_dir}/$file + done +} + +md5sums=('b2b4fd23abb8e9e7382ef9aeab2542f5' + '79ae7fb600e116623a42631d15d66a87' + 'ac82eca7efc9f0ff7e8b976a83692868' + 'f3378832c3ba121f7c9e17dc43c8b1d4' + 'd257f7f20384e894b0431ee61068aa96' + '563c9d1320a3a997db25d3087303dcfb' + '8d6d7eb89a12c449497b209f1a06655b' + '85fc98bd9df02afa0d8a27c01db78c66') diff --git a/PKGBUILD.rostemplate b/PKGBUILD.rostemplate new file mode 100644 index 000000000000..7c0e9489dbbc --- /dev/null +++ b/PKGBUILD.rostemplate @@ -0,0 +1,32 @@ + +pkgdesc='Fill me.' +url='http://www.ros.org/' + +pkgname='ros-groovy-@PACKAGE_NAME@' +pkgver='@STACK_VERSION@' +arch=('i686' 'x86_64') +pkgrel=1 +license=('BSD') +makedepends=('ros-build-tools') + +ros_depends(@ROS_STACK_DEPENDENCIES) +depends=(${ros_depends[@]}) + +source=("@STACK_URL@" + '@STACK_NAME@.patch') +md5sums=('@STACK_MD5@' + '@STACK_PATCH_MD5@') + +source /usr/share/ros-build-tools/stack-install-tools.sh +source /opt/ros/@ROS_DISTRO@/setup.bash + +build() { + export ROS_PACKAGE_PATH=${srcdir}/stacks:$ROS_PACKAGE_PATH + + mkdir -p ${srcdir}/stacks + [ -L ${srcdir}/stacks/@STACK_NAME@ ] || ln -sf ../@STACK_NAME@-${pkgver} ${srcdir}/stacks/@STACK_NAME@ + cd $srcdir/stacks; patch -p0 -i "$srcdir/@STACK_NAME@.patch" + rosmake --no-rosdep -i @STACK_NAME@ + install_ros_stack ${srcdir}/stacks/@STACK_NAME@ /opt/ros/@ROS_DISTRO@/stacks/@STACK_NAME@ +} + diff --git a/create-arch-ros-package-legacy.sh b/create-arch-ros-package-legacy.sh new file mode 100755 index 000000000000..8dc73945d5f2 --- /dev/null +++ b/create-arch-ros-package-legacy.sh @@ -0,0 +1,62 @@ +#!/bin/bash + +set -e + +if [ -z "$3" ]; then + echo "Usage: $0 <distro> <stack> <version>" + exit 1 +fi + +DISTRO=$1 +STACK=$2 +PACKAGE=$(echo $STACK | sed 's/_/-/g') +VERSION=$3 +URL=https://code.ros.org/svn/release/download/stacks/$STACK/$STACK-$VERSION/$STACK-$VERSION.tar.bz2 + +PACKAGE_DIRECTORY=$(pwd)/$STACK + +if [ -d $PACKAGE_DIRECTORY ]; then + read -p "Directory $STACK already exists. Overwrite? (y/n) " + if ! [ "$REPLY" == "y" ]; then + exit 0 + fi +fi + +mkdir -p $PACKAGE_DIRECTORY +cd $PACKAGE_DIRECTORY + +[ -f ${STACK}-${VERSION}.tar.bz2 ] || wget "$URL" +if ! [ -f "${STACK}-${VERSION}.tar.bz2" ]; then + echo "Invalid stack name or version. Downloaded file does not match ${STACK}-${VERSION}.tar.bz2" + exit 1 +fi +MD5=$(md5sum ${STACK}-${VERSION}.tar.bz2 | awk '{print $1}') + +cp /usr/share/ros-build-tools/PKGBUILD.rostemplate $PACKAGE_DIRECTORY/PKGBUILD + +mkdir $PACKAGE_DIRECTORY/tmp +cd $PACKAGE_DIRECTORY/tmp +tar xvjf $PACKAGE_DIRECTORY/${STACK}-${VERSION}.tar.bz2 +cp -r $PACKAGE_DIRECTORY/tmp/${STACK}-${VERSION} $PACKAGE_DIRECTORY/tmp/$STACK +/usr/share/ros-build-tools/fix-python-scripts.sh $PACKAGE_DIRECTORY/tmp/$STACK +diff -Naur ${STACK}-${VERSION} $STACK > $PACKAGE_DIRECTORY/$STACK.patch || true +STACK_DEPENDENCIES=$(/usr/share/ros-build-tools/get-stack-dependencies.py $STACK/stack.xml \ + | sed 's/_/-/g' | sed 's/^/ros-electric-/g' | sed 's/ / ros-electric-/g') +cd $PACKAGE_DIRECTORY +rm -r $PACKAGE_DIRECTORY/tmp + +PATCH_MD5=$(md5sum ${STACK}.patch | awk '{print $1}') + +sed -i "s/@PACKAGE_NAME@/$PACKAGE/g" $PACKAGE_DIRECTORY/PKGBUILD +sed -i "s/@STACK_NAME@/$STACK/g" $PACKAGE_DIRECTORY/PKGBUILD +sed -i "s/@STACK_VERSION@/$VERSION/g" $PACKAGE_DIRECTORY/PKGBUILD +sed -i "s?@STACK_URL@?$URL?g" $PACKAGE_DIRECTORY/PKGBUILD +sed -i "s/@STACK_MD5@/$MD5/g" $PACKAGE_DIRECTORY/PKGBUILD +sed -i "s/@STACK_PATCH_MD5@/$PATCH_MD5/g" $PACKAGE_DIRECTORY/PKGBUILD +sed -i "s/@ROS_DISTRO@/$DISTRO/g" $PACKAGE_DIRECTORY/PKGBUILD +sed -i "s/@ROS_STACK_DEPENDENCIES@/$STACK_DEPENDENCIES/g" $PACKAGE_DIRECTORY/PKGBUILD + +echo "" +echo "PKGBUILD and patch created for stack $STACK." +echo "" +echo "Fill in dependencies and the stack description." diff --git a/fix-python-scripts.sh b/fix-python-scripts.sh new file mode 100755 index 000000000000..2bc55852b364 --- /dev/null +++ b/fix-python-scripts.sh @@ -0,0 +1,17 @@ +#!/bin/bash + +if [ -z "$1" ]; then + echo "Usage: $0 <directory>" + echo "" + echo "Makes sure that all python scripts use the python2 command" + exit 1 +fi + +for file in $(grep -rl 'env python *$' $1); do + if [ -z "$file" ]; then + echo "Error finding files." + exit 1 + fi + sed -i 's/env python *$/env python2/g' $file +done + diff --git a/generate-python-patch.sh b/generate-python-patch.sh new file mode 100755 index 000000000000..b3c9f672802d --- /dev/null +++ b/generate-python-patch.sh @@ -0,0 +1,20 @@ +#!/bin/bash + +set -e + +if [ -z "$1" ]; then + echo "Usage: $0 <stack-archive.tar.bz2>" + exit 1 +fi + +SCRIPT_DIR=$(readlink -f `dirname $0`) +STACK_ARCHIVE_FILE_NAME=$(basename $1) +STACK_ARCHIVE_DIR_NAME=$(readlink -f `dirname $1`) + +STACK_NAME=${1%.tar.bz2} +TMP_DIRECTORY_NAME=$(mktemp -d /tmp/${STACK_NAME}.XXXXXXXXXX) +cd $TMP_DIRECTORY_NAME +tar xjf ${STACK_ARCHIVE_DIR_NAME}/${STACK_ARCHIVE_FILE_NAME} +cp -r ${STACK_NAME} ${STACK_NAME}-orig +$SCRIPT_DIR/fix-python-scripts.sh ${TMP_DIRECTORY_NAME}/${STACK_NAME} +diff -Naur ${STACK_NAME}-orig ${STACK_NAME} diff --git a/generate_packages_makefile.py b/generate_packages_makefile.py new file mode 100755 index 000000000000..b43364ae34b7 --- /dev/null +++ b/generate_packages_makefile.py @@ -0,0 +1,130 @@ +#!/usr/bin/env python + +import os.path +import subprocess +import sys + + +MAKEFILE_TARGET = """ +.PHONY : %(package)s +%(package)s: %(package)s/%(output_file)s + +%(package)s/%(output_file)s: %(dependency_string)s +\tcd %(package)s; makepkg -i +""" + + +class InvalidPackage(Exception): + def __init__(self, package): + self.package = package + + def __str__(self): + return repr(self.package) + + +class Dependency(object): + + def __init__(self, directory_name, package_name, dependencies, output_file): + self.directory_name = directory_name + self.package_name = package_name + self.dependencies = dependencies + self.output_file = output_file + + +class DependencyCache(object): + + def __init__(self): + self._dependencies = {} + + def add_package_directory(self, name): + pkgbuild_file = os.path.realpath(name + '/PKGBUILD') + if not os.path.exists(pkgbuild_file): + raise InvalidPackage(name) + aur_package_name = get_package_name(pkgbuild_file) + if len(aur_package_name) == 0: + raise InvalidPackage(name) + dependencies = get_dependencies(pkgbuild_file) + output_file = get_pkgbuild_output_file(pkgbuild_file) + self._dependencies[aur_package_name] = Dependency( + name, aur_package_name, dependencies, output_file) + + def get_package_names(self): + return list(self._dependencies.keys()) + + def get_packages(self): + return list(self._dependencies.values()) + + def get_package(self, name): + return self._dependencies[name] + + def get_package_directory_name(self, name): + return self._dependencies[name].directory_name + + def get_dependencies(self, package_name, remove_unknown=True): + package_dependencies = self._dependencies.get(package_name) + if package_dependencies is None: + raise InvalidPackage(package_name) + if not remove_unknown: + return package_dependencies + return [self._dependencies[dependency] for dependency in package_dependencies.dependencies + if self._dependencies.get(dependency)] + + +def get_pkgbuild_variable(pkgbuild, variable, is_array=False): + if is_array: + array_string = '[@]' + else: + array_string = '' + with subprocess.Popen( + 'source %s && echo ${%s%s}' % (pkgbuild, variable, array_string), + shell=True, stdout=subprocess.PIPE) as shell_process: + if is_array: + return shell_process.stdout.readline().decode().split() + else: + return shell_process.stdout.readline().decode().strip() + + +def get_pkgbuild_output_file(pkgbuild): + with subprocess.Popen( + 'source %s && echo ${pkgname}-${pkgver}-${pkgrel}-${HOSTTYPE}.pkg.tar.xz' % (pkgbuild), + shell=True, stdout=subprocess.PIPE) as shell_process: + return shell_process.stdout.readline().decode().strip() + + +def get_dependencies(pkgbuild): + return get_pkgbuild_variable(pkgbuild, 'depends', is_array=True) + + +def get_package_name(pkgbuild): + return get_pkgbuild_variable(pkgbuild, 'pkgname') + + +def generate_makefile(cache): + makefile = """ +all: %s +""" % ' '.join(['%s/%s' % (package.directory_name, package.output_file) + for package in cache.get_packages()]) + + for package in cache.get_package_names(): + dependency_string = ' '.join(['%s/%s' % (dependency.directory_name, dependency.output_file) + for dependency in cache.get_dependencies(package)]) + makefile += MAKEFILE_TARGET % {'package': cache.get_package_directory_name(package), + 'output_file': cache.get_package(package).output_file, + 'dependency_string': dependency_string} + return makefile + + +def main(): + if len(sys.argv) < 2: + print('Usage: %s <AUR package>*' % sys.argv[0]) + return 1 + + dependency_cache = DependencyCache() + for arg in sys.argv[1:]: + dependency_cache.add_package_directory(arg) + + print(generate_makefile(dependency_cache)) + + +if __name__ == '__main__': + main() diff --git a/get_stack_dependencies.py b/get_stack_dependencies.py new file mode 100755 index 000000000000..8ad5b2fad816 --- /dev/null +++ b/get_stack_dependencies.py @@ -0,0 +1,55 @@ +#!/usr/bin/env python3 +# Copyright (c) 2012, Lorenz Moesenlechner <moesenle@in.tum.de> +# 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 the Intelligent Autonomous Systems Group/ +# Technische Universitaet Muenchen nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +import xml.dom.minidom as minidom +import sys + + +def main(): + if len(sys.argv) < 2: + print('Usage: %s <stack.xml>' % sys.argv[0]) + return 1 + + top_level = minidom.parse(sys.argv[1]) + if len(top_level.childNodes) != 1 or top_level.childNodes[0].nodeName != 'stack': + print('Invalid stack.xml. No <stack> node found on toplevel.') + return 1 + stack = top_level.childNodes[0] + legacy_dependency_nodes = [n for n in stack.childNodes if n.nodeName == 'depend'] + if legacy_dependency_nodes: + print(*[n.getAttribute('stack') for n in legacy_dependency_nodes], + sep=' ', end='') + else: + dependencies = [n.firstChild.wholeText for n in stack.childNodes + if n.nodeName == 'depends'] + print(*dependencies, sep=' ', end='') + + +if __name__ == '__main__': + main() diff --git a/import_catkin_packages.py b/import_catkin_packages.py new file mode 100755 index 000000000000..e0a15f3d4f71 --- /dev/null +++ b/import_catkin_packages.py @@ -0,0 +1,353 @@ +#!/usr/bin/env python2 + + +from __future__ import print_function + +import catkin_pkg.package +from optparse import OptionParser +import os +import os.path +import subprocess +import urllib2 +import urlparse +import yaml + + +class PackageBase(object): + + def __init__(self, distro, repository_url, name, version): + self.packages = [] + self.distro = distro + self.repository_url = repository_url + package = self._parse_package_file( + self._get_package_xml_url(repository_url, name, version)) + self.name = package.name + self.version = package.version + self.licenses = package.licenses + self.description = package.description + self.dependencies = [self._ensure_python2_dependency(dependency.name) + for dependency in package.build_depends + package.run_depends] + + def _parse_package_file(self, url): + """ + Parses the package.xml file specified by `url`. + + Arguments: + - `url`: Valid URL pointing to a package.xml file. + """ + return catkin_pkg.package.parse_package_string( + urllib2.urlopen(url).read()) + + def _get_ros_dependencies(self): + known_packages = self.distro.package_names(expand_metapackages=True) + return list(set( + [self._rosify_package_name( + 'ros-%s-' % self.distro.name + dependency) + for dependency in self.dependencies if dependency in known_packages])) + + def _get_non_ros_dependencies(self): + known_packages = self.distro.package_names(expand_metapackages=True) + return list(set([dependency for dependency in self.dependencies + if dependency not in known_packages])) + + def _rosify_package_name(self, name): + return name.replace('_', '-') + + def _ensure_python2_dependency(self, dependency): + return dependency.replace('python-', 'python2-') + + def _get_package_xml_url(self, url, name, version): + if url.find('github'): + return github_raw_url(url, 'package.xml', 'release/%s/%s' % (name, version)) + else: + raise 'Unable to generate url for package.xml' + + def generate(self, exclude_dependencies=[]): + raise '`generate` not implemented.' + + +class Package(PackageBase): + BUILD_TEMPLATE = """ +pkgdesc="%(description)s" +url='http://www.ros.org/' + +pkgname='ros-%(distro)s-%(arch_package_name)s' +pkgver='%(package_version)s' +arch=('i686' 'x86_64') +pkgrel=1 +license=('%(license)s') +makedepends=('ros-build-tools') + +ros_depends=(%(ros_package_dependencies)s) +depends=(${ros_depends[@]} + %(other_dependencies)s) + +source=() +md5sums=() + +build() { + [ -f /opt/ros/%(distro)s/setup.bash ] && source /opt/ros/%(distro)s/setup.bash + if [ -d ${srcdir}/%(package_name)s ]; then + cd ${srcdir}/%(package_name)s + git fetch origin --tags + git reset --hard release/%(package_name)s/${pkgver} + else + git clone -b release/%(package_name)s/${pkgver} %(package_url)s ${srcdir}/%(package_name)s + fi + [ -d ${srcdir}/build ] || mkdir ${srcdir}/build + cd ${srcdir}/build + /usr/share/ros-build-tools/fix-python-scripts.sh ${srcdir}/%(package_name)s + cmake ${srcdir}/%(package_name)s -DCATKIN_BUILD_BINARY_PACKAGE=ON -DCMAKE_INSTALL_PREFIX=/opt/ros/%(distro)s -DPYTHON_EXECUTABLE=/usr/bin/python2 -DPYTHON_INCLUDE_DIR=/usr/include/python2.7 -DPYTHON_LIBRARY=/usr/lib/libpython2.7.so -DSETUPTOOLS_DEB_LAYOUT=OFF + make +} + +package() { + cd "${srcdir}/build" + make DESTDIR="${pkgdir}/" install +} +""" + + def generate(self, exclude_dependencies=[]): + ros_dependencies = [dependency for dependency in self._get_ros_dependencies() + if dependency not in exclude_dependencies] + other_dependencies = [dependency for dependency in self._get_non_ros_dependencies() + if dependency not in exclude_dependencies] + return self.BUILD_TEMPLATE % { + 'distro': self.distro.name, + 'arch_package_name': self._rosify_package_name(self.name), + 'package_name': self.name, + 'package_version': self.version, + 'package_url': self.repository_url, + 'license': ', '.join(self.licenses), + 'description': self.description.replace('"', '\\"').replace('`', '\`'), + 'ros_package_dependencies': '\n '.join(ros_dependencies), + 'other_dependencies': '\n '.join(other_dependencies) + } + + +class MetaPackage(PackageBase): + BUILD_TEMPLATE = """ +pkgdesc="%(description)s" +url='http://www.ros.org/' + +pkgname='ros-%(distro)s-%(arch_package_name)s' +pkgver='%(package_version)s' +arch=('i686' 'x86_64') +pkgrel=1 +license=('%(license)s') +makedepends=('ros-build-tools') + +ros_depends=(%(ros_package_dependencies)s) +depends=(${ros_depends[@]} + %(other_dependencies)s) + +source=() +md5sums=() + +""" + + def __init__(self, distro, repository_url, name, version): + super(MetaPackage, self).__init__(distro, repository_url, name, version) + self.packages = [Package(distro, repository_url, child_name, version) + for child_name in distro.meta_package_package_names(name)] + + def generate(self, exclude_dependencies=[]): + ros_dependencies = [dependency for dependency in self._get_ros_dependencies() + if dependency not in exclude_dependencies] + other_dependencies = [dependency for dependency in self._get_non_ros_dependencies() + if dependency not in exclude_dependencies] + return self.BUILD_TEMPLATE % { + 'distro': self.distro.name, + 'arch_package_name': self._rosify_package_name(self.name), + 'package_name': self.name, + 'package_version': self.version, + 'license': ', '.join(self.licenses), + 'description': self.description.replace('"', '\"'), + 'ros_package_dependencies': '\n '.join(ros_dependencies), + 'other_dependencies': '\n '.join(other_dependencies) + } + + +class DistroDescription(object): + + def __init__(self, name, url): + stream = urllib2.urlopen(url) + self.name = name + self._distro = yaml.load(stream) + self._package_cache = {} + if self.name != self._distro['release-name']: + raise 'ROS distro names do not match (%s != %s)' % (self.name, self._distro['release-name']) + + def package_names(self, expand_metapackages=False): + packages = [name for name in self._distro['repositories'].keys()] + if expand_metapackages: + return sum([([name] + self.meta_package_package_names(name)) if self._is_meta_package(name) else [name] + for name in packages], + []) + else: + return packages + + def is_package(self, name): + return self._get_package_data(name) != None + + def package(self, name): + package_data = self._get_package_data(name) + if not package_data: + raise 'Unable to find package `%s`' % name + if self._package_cache.get(name): + return self._package_cache[name] + url = package_data['url'] + version = package_data['version'].split('-')[0] + if self._is_meta_package(name): + package = MetaPackage(self, url, name, version) + else: + package = Package(self, url, name, version) + self._package_cache[name] = package + return package + + def meta_package_package_names(self, name): + return self._distro['repositories'][name]['packages'].keys() + + def _is_meta_package(self, name): + if self._distro['repositories'].get(name): + return (self._distro['repositories'][name].get('packages') != None) + + def _get_package_data(self, name): + """Searches for `name` in all known packages and metapackages.""" + if self._distro['repositories'].get(name): + return self._distro['repositories'][name] + else: + for package in self.package_names(): + if (self._is_meta_package(package) + and name in self._distro['repositories'][package]['packages']): + return self._distro['repositories'][package] + + +def list_packages(distro_description): + print(*distro_description.package_names(), sep='\n') + + +### From http://code.activestate.com/recipes/577058/ (r2) +def query_yes_no(question, default="yes"): + """Ask a yes/no question via raw_input() and return their answer. + + "question" is a string that is presented to the user. + "default" is the presumed answer if the user just hits <Enter>. + It must be "yes" (the default), "no" or None (meaning + an answer is required of the user). + + The "answer" return value is one of "yes" or "no". + """ + valid = {"yes":"yes", "y":"yes", "ye":"yes", + "no":"no", "n":"no"} + if default == None: + prompt = " [y/n] " + elif default == "yes": + prompt = " [Y/n] " + elif default == "no": + prompt = " [y/N] " + else: + raise ValueError("invalid default answer: '%s'" % default) + while True: + print(question + prompt) + choice = raw_input().lower() + if default is not None and choice == '': + return default + elif choice in valid.keys(): + return valid[choice] + else: + print("Please respond with 'yes' or 'no' (or 'y' or 'n').") + + +def github_raw_url(repo_url, path, commitish): + """ + Returns the URL of the file blob corresponding to `path` in the + github repository `repo_url` in branch, commit or tag `commitish`. + """ + url = urlparse.urlsplit(repo_url) + return 'https://raw.%(host)s%(repo_path)s/%(branch)s/%(path)s' % { + 'host': url.hostname, + 'repo_path': url.path.replace('.git', ''), + 'branch': commitish, + 'path': path + } + + +def generate_pkgbuild(distro, package, directory, force=False, + no_overwrite=False, recursive=False, exclude_dependencies=[], + generated=None): + if generated is None: + generated = [] + elif package.name in generated: + return + generated.append(package.name) + if package.packages: + for child_package in package.packages: + generate_pkgbuild(distro, child_package, directory, + force=force, exclude_dependencies=exclude_dependencies, + no_overwrite=no_overwrite, recursive=recursive, + generated=generated) + if recursive: + for dependency in package.dependencies: + if distro.is_package(dependency): + generate_pkgbuild(distro, distro.package(dependency), directory, + force=force, no_overwrite=no_overwrite, recursive=recursive, + exclude_dependencies=exclude_dependencies, + generated=generated) + output_directory = os.path.join(directory, package.name) + if not os.path.exists(output_directory): + os.mkdir(output_directory) + if os.path.exists(os.path.join(output_directory, 'PKGBUILD')): + if no_overwrite: + return + if not force and not query_yes_no( + "Directory '%s' already contains a PKGBUILD file. Overwrite?" % ( + output_directory)): + return + print('Generating PKGBUILD for package %s.' % package.name) + with open(os.path.join(output_directory, 'PKGBUILD'), 'w') as pkgbuild: + pkgbuild.write(package.generate(exclude_dependencies)) + + +def main(): + parser = OptionParser(usage='usage: %prog [options] PACKAGE...') + parser.add_option('--distro', default='groovy', metavar='distro', + help='Select the ROS distro to use.') + parser.add_option('--list-packages', dest='list_packages', action='store_true', + default=False, help='Lists all available packages.') + parser.add_option('--output-directory', metavar='output_directory', default='.', + help='The output directory. Packages are put into <output-directory>/<name>') + parser.add_option( + '--distro-url', metavar='distro_url', + default='https://raw.github.com/ros/rosdistro/master/releases/%s.yaml', + help='The URL of the distro description. %s is replaced by the actual distro name') + parser.add_option( + '--exclude-dependencies', metavar='exclude_dependencies', + default='python2-catkin-pkg,python2-rospkg,python2-rosdep', + help='Comma-separated list of (source) package dependencies to exclude from the generated PKGBUILD file.') + parser.add_option('-f', '--force', dest='force', action='store_true', default=False, + help='Always overwrite exiting PKGBUILD files.') + parser.add_option('-n', '--no-overwrite', dest='no_overwrite', action='store_true', default=False, + help='Do not overwrite PKGBUILD files.') + parser.add_option('--recursive', dest='recursive', action='store_true', default=False, + help='Recursively import dependencies') + options, args = parser.parse_args() + + distro = DistroDescription( + options.distro, url=options.distro_url % options.distro) + if options.list_packages: + list_packages(distro) + return + elif args: + for package in args: + generate_pkgbuild(distro, distro.package(package), + os.path.abspath(options.output_directory), + exclude_dependencies=options.exclude_dependencies.split(','), + force=options.force, no_overwrite=options.no_overwrite, + recursive=options.recursive) + else: + parser.error('No packages specified.') + + +if __name__ == '__main__': + main() diff --git a/stack-install-tools.sh b/stack-install-tools.sh new file mode 100644 index 000000000000..1bbb4212f4d6 --- /dev/null +++ b/stack-install-tools.sh @@ -0,0 +1,56 @@ +# Copyright (c) 2012, Lorenz Moesenlechner <moesenle@in.tum.de> +# 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 the Intelligent Autonomous Systems Group/ +# Technische Universitaet Muenchen 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. + +install_ros_stack() { + if [ -z "$1" ] || [ -z "$2" ]; then + echo "Usage: install_ros_stack <src-dir> <ros-dir>" + exit 1 + fi + + mkdir -p $pkgdir/$2 + cp -r $1/* $pkgdir/$2 + find $pkgdir/$2 -name manifest.xml -printf '%h/build\n' | xargs rm -rf + fix_rpaths $1 $2 +} + +fix_rpaths() { + if [ -z "$1" ] || [ -z "$2" ]; then + echo "Usage: fix_rpaths <src-dir> <ros-dir>" + exit 1 + fi + + executables=$(find $pkgdir/$2 -type f -executable) + for file in $executables; do + rpath_output=$(chrpath -l $file 2>/dev/null || echo "") + if [ -n "$rpath_output" ] && echo $rpath_output | grep RPATH; then + fixed_rpath=$(echo $rpath_output | sed 's/.*RPATH=//g' | sed "s?$1?$2?g") + chrpath -r $fixed_rpath $file + fi + done +} + |