summarylogtreecommitdiffstats
diff options
context:
space:
mode:
authorBenjamin Chrétien2015-08-26 16:36:42 +0900
committerBenjamin Chrétien2015-08-26 16:36:42 +0900
commitfb12a3cec58991399872ff23a68df2f9489e3932 (patch)
tree9e6392ed9098f18ece762ae441a24ae07c22b2ec
parentd04f9936dffd8825f583e1c26eb7d7d7b120b73c (diff)
downloadaur-fb12a3cec58991399872ff23a68df2f9489e3932.tar.gz
Move import_catkin_packages.py to arch-ros-stacks
-rw-r--r--.SRCINFO11
-rw-r--r--PKGBUILD11
-rwxr-xr-ximport_catkin_packages.py819
3 files changed, 4 insertions, 837 deletions
diff --git a/.SRCINFO b/.SRCINFO
index ea594000ac88..32cd00b62ad5 100644
--- a/.SRCINFO
+++ b/.SRCINFO
@@ -1,17 +1,12 @@
pkgbase = ros-build-tools
pkgdesc = Utilities for building arch packages for ROS stacks.
- pkgver = 0.1.2
+ pkgver = 0.2.0
pkgrel = 1
url = https://github.com/bchretien/arch-ros-stacks
arch = i686
arch = x86_64
license = BSD
- optdepends = python2: package generation
- optdepends = python2-catkin_pkg: package generation
- optdepends = python2-certifi: package generation
- optdepends = python2-termcolor: package generation
- optdepends = python2-urllib3: package generation
- optdepends = python2-yaml: package generation
+ optdepends = python2
source = fix-python-scripts.sh
source = stack-install-tools.sh
source = create-arch-ros-package-legacy.sh
@@ -19,7 +14,6 @@ pkgbase = ros-build-tools
source = get_stack_dependencies.py
source = generate_packages_makefile.py
source = generate-python-patch.sh
- source = import_catkin_packages.py
source = clear-ros-env.sh
md5sums = ed01573e0ecc0f7ca451d7e2849cc5ee
md5sums = 79ae7fb600e116623a42631d15d66a87
@@ -28,7 +22,6 @@ pkgbase = ros-build-tools
md5sums = d257f7f20384e894b0431ee61068aa96
md5sums = 563c9d1320a3a997db25d3087303dcfb
md5sums = 8d6d7eb89a12c449497b209f1a06655b
- md5sums = 590922c9cb12d6e2f8e295df241e08ef
md5sums = 07f5253eb3f8cb5295c32026a20ab6c0
pkgname = ros-build-tools
diff --git a/PKGBUILD b/PKGBUILD
index bbc1a70c7130..28d915f56e98 100644
--- a/PKGBUILD
+++ b/PKGBUILD
@@ -5,18 +5,13 @@ pkgdesc='Utilities for building arch packages for ROS stacks.'
url="https://github.com/bchretien/arch-ros-stacks"
pkgname='ros-build-tools'
-pkgver='0.1.2'
+pkgver='0.2.0'
arch=('i686' 'x86_64')
pkgrel=1
license=('BSD')
makedepends=()
depends=()
-optdepends=('python2: package generation'
- 'python2-catkin_pkg: package generation'
- 'python2-certifi: package generation'
- 'python2-termcolor: package generation'
- 'python2-urllib3: package generation'
- 'python2-yaml: package generation')
+optdepends=('python2')
pkg_destination_dir="/usr/share/ros-build-tools"
@@ -27,7 +22,6 @@ source=('fix-python-scripts.sh'
'get_stack_dependencies.py'
'generate_packages_makefile.py'
'generate-python-patch.sh'
- 'import_catkin_packages.py'
'clear-ros-env.sh')
build() {
@@ -48,5 +42,4 @@ md5sums=('ed01573e0ecc0f7ca451d7e2849cc5ee'
'd257f7f20384e894b0431ee61068aa96'
'563c9d1320a3a997db25d3087303dcfb'
'8d6d7eb89a12c449497b209f1a06655b'
- '590922c9cb12d6e2f8e295df241e08ef'
'07f5253eb3f8cb5295c32026a20ab6c0')
diff --git a/import_catkin_packages.py b/import_catkin_packages.py
deleted file mode 100755
index 4aeda23603dc..000000000000
--- a/import_catkin_packages.py
+++ /dev/null
@@ -1,819 +0,0 @@
-#!/usr/bin/env python
-# -*- coding: utf-8 -*-
-# vim:set et sw=4 ts=2 shiftwidth=2:
-
-from __future__ import print_function
-
-import catkin_pkg.package
-from optparse import OptionParser
-import sys
-import os
-import os.path
-import urllib3
-import yaml
-import re
-from collections import OrderedDict
-from termcolor import colored, cprint
-import pickle
-import subprocess
-
-# Directory containing some data files
-updates_packages_dir = "/tmp/import_catkin_packages"
-
-# File that contains the dump file of updated packages
-updated_packages_filename = os.path.join(updates_packages_dir,
- "updated_packages_%(distro)s.dump")
-
-# File that contains the list of packages to install
-makepkg_filename = os.path.join(updates_packages_dir,
- "makepkg_%(distro)s.dump")
-
-http = urllib3.PoolManager()
-
-try:
- import certifi
-
- # Make verified HTTPS requests
- http = urllib3.PoolManager(
- cert_reqs='CERT_REQUIRED', # Force certificate check.
- ca_certs=certifi.where(), # Path to the Certifi bundle.
- )
-except ImportError as e:
- # HTTPS requests will not be verified
- pass
-
-
-class PackageBase(object):
-
- def __init__(self, distro, repository_url, name, version, version_patch):
- 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.version_patch = version_patch
- self.package_release = str(int(version_patch) + 1)
- self.licenses = package.licenses
- self.run_dependencies = list(OrderedDict.fromkeys([dependency.name for dependency in package.run_depends]))
- self.build_dependencies = list(OrderedDict.fromkeys([dependency.name for dependency in package.build_depends + package.buildtool_depends]))
-
- # This may be the case for some metapackages
- self.is_virtual = False
-
- # Build dependencies already added:
- if 'git' in self.build_dependencies:
- self.build_dependencies.remove('git')
- if 'cmake' in self.build_dependencies:
- self.build_dependencies.remove('cmake')
-
- # Remove HTML tags from description
- self.description = re.sub('<[^<]+?>', '', package.description)
- # Put it on one line to motivate packagers to make shorter descriptions
- self.description = re.sub('\n', ' ', self.description)
- # Convert tabs to spaces
- self.description = re.sub('\t', ' ', self.description)
- # Multiple consecutive spaces turned into one
- self.description = re.sub('([ ]+)', ' ', self.description)
- # Only take the first sentence (keep short description)
- self.description = re.split("\. |\.$", self.description)[0] + "."
- # Handle quotes
- self.description = self.description.replace('"', '').replace('`', '').replace('&quot;', '').replace('\'','')
-
- # Website URL
- self.site_url = "http://www.ros.org/"
- for url in package.urls:
- if url.type == "website":
- # Some maintainers provide wrong URLs...
- url.url = re.findall('http[s]?://(?:[a-zA-Z]|[0-9]|[$-_@.&+]|[!*\(\),]'
- '|(?:%[0-9a-fA-F][0-9a-fA-F]))+', url.url)
- if url.url:
- self.site_url = url.url[0]
-
- 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(http.request('GET', url).data)
-
- def _fix_dependencies(self, rosdep_urls, build_dep, run_dep):
- # Fix usual non-ROS dependencies:
- # - load replacement dictionary: these are found in rosdep yaml files. We
- # just need to download and merge these files
- # in a dictionary.
- dependency_map = self._get_rosdep_dictionary(rosdep_urls)
-
- def _fix_dependencies_with_map(dependencies):
- fixed_dependencies = set()
- # - replace in other_dependencies
- for index, dep in enumerate(dependencies):
- if (dep in dependency_map):
- # The map may replace one package by multiple ones, or even by none
- for package in dependency_map[dep]:
- fixed_dependencies.add(package)
- else:
- fixed_dependencies.add(dep)
-
- # Fix some possibly missing Python 2/3 package conflicts
- if self.distro.python_major() == "2":
- fixed_dependencies = [self._ensure_python2_dependency(dependency)
- for dependency in fixed_dependencies]
- elif self.distro.python_major() == "3":
- fixed_dependencies = [self._ensure_python3_dependency(dependency)
- for dependency in fixed_dependencies]
- return fixed_dependencies
-
- fixed_build_dep = _fix_dependencies_with_map(build_dep)
- fixed_run_dep = _fix_dependencies_with_map(run_dep)
-
- return fixed_build_dep, fixed_run_dep
-
- def _get_ros_dependencies(self):
- """
- Returns (build_dependencies, run_dependencies)
- """
- known_packages = self.distro.package_names(expand_metapackages=True)
- build_dep = list(set([self._get_full_package_name(dependency)
- for dependency in self.build_dependencies if dependency in known_packages]))
- run_dep = list(set([self._get_full_package_name(dependency)
- for dependency in self.run_dependencies if dependency in known_packages]))
- return build_dep, run_dep
-
- def _get_non_ros_dependencies(self, rosdep_urls=[]):
- """
- Returns (build_dependencies, run_dependencies)
- """
- known_packages = self.distro.package_names(expand_metapackages=True)
-
- other_build_dep = list(set([dependency for dependency in self.build_dependencies
- if dependency not in known_packages]))
- other_run_dep = list(set([dependency for dependency in self.run_dependencies
- if dependency not in known_packages]))
- return self._fix_dependencies(rosdep_urls, other_build_dep, other_run_dep)
-
- def _rosify_package_name(self, name):
- return name.replace('_', '-')
-
- def _get_full_package_name(self, name):
- return "ros-%s-%s" % (self.distro.name, name.replace('_', '-'))
-
- def _ensure_python2_dependency(self, dependency):
- # python ---> python2
- # python-foo ---> python2-foo
- return re.sub(r'^python(?!2)([a-zA-Z0-9\-]*)', r'python2\1', dependency)
-
- def _ensure_python3_dependency(self, dependency):
- # python2 ---> python
- # python2-foo ---> python-foo
- return re.sub(r'^python2([a-zA-Z0-9\-]*)', r'python\1', dependency)
-
- def _get_package_xml_url(self, url, name, version):
- if url.find('github'):
- if self.distro.name != "fuerte":
- return github_raw_url(url, 'package.xml', 'release/%s/%s' % (self.distro.name, name))
- else: # fuerte-specific
- return github_raw_url(url, 'package.xml', 'release/%s/%s' % (name, version))
- else:
- raise Exception('Unable to generate url for package.xml')
-
- def _get_rosdep_dictionary(self, rosdep_urls):
- dependency_map = {}
- for rosdep_url in rosdep_urls:
- stream = http.request('GET', rosdep_url).data
- rosdep_file = yaml.load(stream)
- for package_name, distrib in rosdep_file.items():
- if 'arch' in distrib:
- if 'pacman' in distrib["arch"]:
- dependency_map[package_name] = distrib["arch"]["pacman"]["packages"]
- elif 'aur' in distrib["arch"]:
- dependency_map[package_name] = distrib["arch"]["aur"]["packages"]
- else:
- dependency_map[package_name] = distrib["arch"]
- return dependency_map
-
- def generate(self, exclude_dependencies=[], rosdep_urls=[]):
- raise Exception('`generate` not implemented.')
-
- def is_same_version(self, pkgbuild_file):
- """
- Checks whether a currently installed PKGBUILD contains the same version.
- """
- if os.path.isfile(pkgbuild_file):
- f = open(pkgbuild_file, "r")
- content = f.read()
- pattern_pkgver = re.compile(r"pkgver='([0-9\.]*)'")
- pattern_pkgver_patch = re.compile(r"_pkgver_patch=([0-9]*)")
- match_pkgver = re.search(pattern_pkgver, content)
- match_pkgver_patch = re.search(pattern_pkgver_patch, content)
- if match_pkgver and match_pkgver_patch:
- return (match_pkgver.group(1) == self.version
- and match_pkgver_patch.group(1) == self.version_patch)
- else:
- return False
- else:
- return False
-
-
-class Package(PackageBase):
- BUILD_TEMPLATE = """# Script generated with import_catkin_packages.py
-# For more information: https://github.com/bchretien/arch-ros-stacks
-pkgdesc="ROS - %(description)s"
-url='%(site_url)s'
-
-pkgname='ros-%(distro)s-%(arch_package_name)s'
-pkgver='%(package_version)s'
-_pkgver_patch=%(package_version_patch)s
-arch=('any')
-pkgrel=%(package_release)s
-license=('%(license)s')
-
-ros_makedepends=(%(ros_build_dependencies)s)
-makedepends=('cmake' 'git' 'ros-build-tools'
- ${ros_makedepends[@]}
- %(other_build_dependencies)s)
-
-ros_depends=(%(ros_run_dependencies)s)
-depends=(${ros_depends[@]}
- %(other_run_dependencies)s)
-
-_tag=release/%(distro)s/%(package_name)s/${pkgver}-${_pkgver_patch}
-_dir=%(package_name)s
-source=("${_dir}"::"git+%(package_url)s"#tag=${_tag})
-md5sums=('SKIP')
-
-build() {
- # Use ROS environment variables
- source /usr/share/ros-build-tools/clear-ros-env.sh
- [ -f /opt/ros/%(distro)s/setup.bash ] && source /opt/ros/%(distro)s/setup.bash
-
- # Create build directory
- [ -d ${srcdir}/build ] || mkdir ${srcdir}/build
- cd ${srcdir}/build
-
- # Fix Python2/Python3 conflicts
- /usr/share/ros-build-tools/fix-python-scripts.sh -v %(python_version_major)s ${srcdir}/${_dir}
-
- # Build project
- cmake ${srcdir}/${_dir} \\
- -DCMAKE_BUILD_TYPE=Release \\
- -DCATKIN_BUILD_BINARY_PACKAGE=ON \\
- -DCMAKE_INSTALL_PREFIX=/opt/ros/%(distro)s \\
- -DPYTHON_EXECUTABLE=%(python_executable)s \\
- -DPYTHON_INCLUDE_DIR=%(python_include_dir)s \\
- -DPYTHON_LIBRARY=%(python_library)s \\
- -DPYTHON_BASENAME=%(python_basename)s \\
- -DSETUPTOOLS_DEB_LAYOUT=OFF
- make
-}
-
-package() {
- cd "${srcdir}/build"
- make DESTDIR="${pkgdir}/" install
-}
-"""
-
- def generate(self, python_version, exclude_dependencies=[], rosdep_urls=[]):
- raw_build_dep, raw_run_dep = self._get_ros_dependencies()
- ros_build_dep = [dependency for dependency in raw_build_dep
- if dependency not in exclude_dependencies]
- ros_run_dep = [dependency for dependency in raw_run_dep
- if dependency not in exclude_dependencies]
-
- other_raw_build_dep, other_raw_run_dep = self._get_non_ros_dependencies(rosdep_urls)
- other_build_dep = [dependency for dependency in other_raw_build_dep
- if dependency not in exclude_dependencies]
- other_run_dep = [dependency for dependency in other_raw_run_dep
- if dependency not in exclude_dependencies]
-
- python_version_major = python_version.split('.')[0]
- python_version_full = python_version
- # Python 3 include directory is /usr/include/python3.4m... Because why not?
- if python_version_major == "3":
- python_version_full = "%s%s" % (python_version_full, "m")
-
- # PYTHON_BASENAME for PySide:
- # If Python 2.7: PySideConfig{-python2.7}.cmake
- python_basename = "-python2.7"
- if python_version_major == "3":
- # If Python 3.4: PySideConfig{.cpython-34m}.cmake
- python_basename = ".cpython-%s" % (python_version_full.replace(".", ""))
-
-
- pkgbuild = 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_version_patch': self.version_patch,
- 'package_release': self.package_release,
- 'package_url': self.repository_url,
- 'license': ', '.join(self.licenses),
- 'description': self.description,
- 'site_url': self.site_url,
- 'ros_build_dependencies': '\n '.join(ros_build_dep),
- 'ros_run_dependencies': '\n '.join(ros_run_dep),
- 'other_build_dependencies': '\n '.join(other_build_dep),
- 'other_run_dependencies': '\n '.join(other_run_dep),
- 'python_version_major': python_version_major,
- 'python_executable': '/usr/bin/python%s' % python_version_major,
- 'python_include_dir': '/usr/include/python%s' % python_version_full,
- 'python_library': '/usr/lib/libpython%s.so' % python_version_full,
- 'python_basename': python_basename
- }
-
- # Post-processing:
- # Remove useless carriage return
- pkgbuild = re.sub('\\n \)', ')', pkgbuild)
- return pkgbuild
-
-
-class MetaPackage(PackageBase):
- BUILD_TEMPLATE = """# Script generated with import_catkin_packages.py
-# For more information: https://github.com/bchretien/arch-ros-stacks
-pkgdesc="ROS - %(description)s"
-url='%(site_url)s'
-
-pkgname='ros-%(distro)s-%(arch_package_name)s'
-pkgver='%(package_version)s'
-arch=('any')
-pkgrel=%(package_release)s
-license=('%(license)s')
-
-ros_makedepends=(%(ros_build_dependencies)s)
-makedepends=('cmake' 'git' 'ros-build-tools'
- ${ros_makedepends[@]}
- %(other_build_dependencies)s)
-
-ros_depends=(%(ros_run_dependencies)s)
-depends=(${ros_depends[@]}
- %(other_run_dependencies)s)
-
-source=()
-md5sums=()
-"""
-
- def __init__(self, distro, repository_url, name, version, version_patch):
- try:
- super(MetaPackage, self).__init__(distro, repository_url, name, version,
- version_patch)
- except urllib3.HTTPError:
- # Virtual metapackage
- # TODO: there should be a cleaner way to deal with this...
- self.name = name
- self.is_virtual = True
- self.packages = [Package(distro, repository_url, child_name, version, version_patch)
- for child_name in distro.meta_package_package_names(name)]
-
- def generate(self, exclude_dependencies=[], rosdep_urls=[]):
- raw_build_dep, raw_run_dep = self._get_ros_dependencies()
- ros_build_dep = [dependency for dependency in raw_build_dep
- if dependency not in exclude_dependencies]
- ros_run_dep = [dependency for dependency in raw_run_dep
- if dependency not in exclude_dependencies]
-
- other_raw_build_dep, other_raw_run_dep = self._get_non_ros_dependencies(rosdep_urls)
- other_build_dep = [dependency for dependency in other_raw_build_dep
- if dependency not in exclude_dependencies]
- other_run_dep = [dependency for dependency in other_raw_run_dep
- if dependency not in exclude_dependencies]
- pkgbuild = 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_version_patch': self.version_patch,
- 'package_release': self.package_release,
- 'license': ', '.join(self.licenses),
- 'description': self.description,
- 'site_url': self.site_url,
- 'ros_build_dependencies': '\n '.join(ros_build_dep),
- 'ros_run_dependencies': '\n '.join(ros_run_dep),
- 'other_build_dependencies': '\n '.join(other_build_dep),
- 'other_run_dependencies': '\n '.join(other_run_dep)
- }
-
- # Post-processing:
- # Remove useless carriage return
- pkgbuild = re.sub('\${ros_depends\[@\]}\\n \)',
- '${ros_depends[@]})', pkgbuild)
- return pkgbuild
-
-
-class DistroDescription(object):
-
- def __init__(self, name, url, python_version):
- stream = http.request('GET', url).data
- self.name = name
- self._distro = yaml.load(stream)
- self._package_cache = {}
- self.python_version = python_version
- if self.name == "fuerte":
- if self.name != self._distro['release-name']:
- raise Exception('ROS distro names do not match (%s != %s)' % (self.name, self._distro['release-name']))
- # process "metapackages"
- if 'metapackages' in self._distro['repositories'].keys():
- metapackages = self._distro['repositories']['metapackages']['release']
- for meta in metapackages['packages']:
- self._distro['repositories'][meta] = {}
- self._distro['repositories'][meta]['release'] = {}
- self._distro['repositories'][meta]['release']['url'] = metapackages['url']
- self._distro['repositories'][meta]['release']['version'] = metapackages['version']
- del self._distro['repositories']['metapackages']
-
-
- 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 Exception('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]
- version_patch = package_data['version'].split('-')[1]
- # WARNING: some metapackages embed a package with the same name. In this case,
- # we treat the package as a normal package.
- if self._is_meta_package(name) and (not name in self._distro['repositories'][name]['release']['packages']):
- package = MetaPackage(self, url, name, version, version_patch)
- else:
- package = Package(self, url, name, version, version_patch)
- self._package_cache[name] = package
- return package
-
- def meta_package_package_names(self, name):
- return self._distro['repositories'][name]['release']['packages']
-
- def python_major(self):
- """
- Return the major version number of Python.
- """
- return self.python_version.split('.')[0]
-
- def _is_meta_package(self, name):
- if self._distro['repositories'].get(name) != None:
- if self._distro['repositories'][name].get('release') != None:
- return (self._distro['repositories'][name]['release'].get('packages') != None)
-
- def _get_package_data(self, name):
- """
- Searches for `name` in all known packages and metapackages.
- """
- if self._distro['repositories'].get(name):
- try:
- return self._distro['repositories'][name]['release']
- except KeyError as e:
- print (colored("Missing %s branch for %s" % (e, name),
- 'red', attrs=['bold']))
- else:
- for package in self.package_names():
- if (self._is_meta_package(package)
- and name in self._distro['repositories'][package]['release']['packages']):
- return self._distro['repositories'][package]['release']
-
-
-def list_packages(distro_desc, distro_dir=None):
- """
- List available packages.
- """
- if not distro_dir or not os.path.isdir(distro_dir):
- print(*sorted(distro_desc.package_names()), sep='\n')
- else:
- # For each package, check if a PKGBUILD has already been generated
- for name in sorted(distro_desc.package_names()):
- if os.path.isfile(os.path.join(distro_dir, name, "PKGBUILD")):
- print("[✓] %s" % (colored(name, 'green', attrs=['bold'])))
- else:
- print("[ ] %s" % name)
-
-
-### 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 = urllib3.util.parse_url(repo_url)
- return 'https://raw.%(host)s%(repo_path)s/%(branch)s/%(path)s' % {
- 'host': url.host,
- 'repo_path': url.path.replace('.git', ''),
- 'branch': commitish,
- 'path': path
- }
-
-
-def create_submodule(url_ro, url_rw, full_dir):
- parent_dir = os.path.dirname(full_dir)
- relative_dir = os.path.basename(full_dir)
- # First call may fail if the remote AUR package does not exist yet
- fail = subprocess.call(['git', '-C', parent_dir, 'submodule', 'add', '--force',
- url_ro, relative_dir], stderr=subprocess.PIPE,
- stdout=subprocess.PIPE)
- if fail:
- subprocess.check_call(['git', '-C', parent_dir, 'submodule', 'add', '--force',
- url_ro, relative_dir], stdout=subprocess.PIPE)
- subprocess.check_call(['git', '-C', full_dir, 'remote', 'set-url', '--push',
- 'origin', url_rw], stderr=subprocess.PIPE,
- stdout=subprocess.PIPE)
-
-
-def create_clone(url_ro, url_rw, full_dir):
- subprocess.check_call(['git', 'clone', url_ro, full_dir],
- stderr=subprocess.PIPE, stdout=subprocess.PIPE)
- subprocess.check_call(['git', '-C', full_dir, 'remote', 'set-url', '--push',
- 'origin', url_rw], stderr=subprocess.PIPE,
- stdout=subprocess.PIPE)
-
-
-def create_package_directory(directory, package):
- """
- Create a directory or an AUR submodule based on the context.
- """
- full_dir = os.path.join(directory, package.name)
-
- full_package_name = package._get_full_package_name(package.name)
- url_ro = "https://aur.archlinux.org/%s.git" % (full_package_name)
- url_rw = "ssh+git://aur@aur.archlinux.org/%s.git" % (full_package_name)
-
- is_git_dir = subprocess.call(['git', '-C', directory, 'rev-parse', '--is-inside-work-tree'],
- stdout=subprocess.PIPE, stderr=subprocess.PIPE) == 0
-
- if not os.path.exists(full_dir):
- if not is_git_dir:
- create_clone(url_ro, url_rw, full_dir)
- else:
- create_submodule(url_ro, url_rw, full_dir)
-
- return full_dir
-
-
-def generate_pkgbuild(distro, package, directory, force=False,
- no_overwrite=False, recursive=False, update=False,
- exclude_dependencies=[], rosdep_urls=[],
- generated=None, written=None):
- """
- Generate a PKGBUILD file for the given package and the given ROS
- distribution.
- """
- if generated is None:
- generated = set()
- elif package.name in generated:
- return
-
- generated.add(package.name)
-
- if distro._is_meta_package(package.name):
- for child_name in distro.meta_package_package_names(package.name):
- generate_pkgbuild(distro, distro.package(child_name), directory,
- force=force,
- exclude_dependencies=exclude_dependencies,
- no_overwrite=no_overwrite, recursive=recursive,
- update=update, rosdep_urls=rosdep_urls,
- generated=generated, written=written)
-
- # If this is a virtual package (i.e. not an actual package)
- if package.is_virtual:
- return
-
- if recursive:
- for dependency in package.run_dependencies + package.build_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, update=update,
- rosdep_urls=rosdep_urls, generated=generated,
- written=written)
-
- # If the directory/submodule does not exist, create it
- output_directory = create_package_directory(directory, package)
-
- # If PKGBUILD already exists
- if os.path.exists(os.path.join(output_directory, 'PKGBUILD')):
- if no_overwrite:
- return
- if not force and query_yes_no(
- "Directory '%s' already contains a PKGBUILD file. Overwrite?" % (
- output_directory)) == "no":
- return
-
- pkgbuild_file = os.path.join(output_directory, 'PKGBUILD')
-
- # If we are merely updating packages
- if update:
- if package.is_same_version(pkgbuild_file):
- print('PKGBUILD for package %s already up-to-date (%s)'
- % (colored(package.name, 'yellow', attrs=['bold']),
- colored(package.version + '-' + package.version_patch, 'white',
- attrs=['bold'])))
- return
-
- print('Generating PKGBUILD for package %s (%s)'
- % (colored(package.name, 'green', attrs=['bold']),
- colored(package.version + '-' + package.version_patch, 'white',
- attrs=['bold'])))
-
- # Write PKGBUILD file
- with open(pkgbuild_file, 'w') as pkgbuild:
- pkgbuild.write(package.generate(distro.python_version, exclude_dependencies,
- rosdep_urls))
-
- # Add the package to the txt file containing packages to install
- if written:
- written["packages"].append(package.name)
-
-
-
-def main():
- parser = OptionParser(usage='usage: %prog [options] PACKAGE...')
- parser.add_option('--distro', default='hydro', 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=None,
- help='The output directory. Packages are put into '
- '<output-directory>/<name>')
- default_distro_url = 'https://raw.github.com/ros/rosdistro/master/%s/distribution.yaml'
- parser.add_option('--distro-url', metavar='distro_url',
- default=default_distro_url,
- help='The URL of the distro description. %s is replaced by '
- 'the actual distro name')
- default_rosdep_url = 'https://raw.github.com/ros/rosdistro/master/rosdep/%s.yaml'
- parser.add_option('--rosdep-urls', metavar='rosdep_urls',
- default=[default_rosdep_url % 'base',
- default_rosdep_url % 'python',
- default_rosdep_url % 'ruby'],
- help='The URLs of the rosdep mapping files.')
- parser.add_option('--exclude-dependencies', metavar='exclude_dependencies',
- default='',
- help='Comma-separated list of (source) package dependencies'
- ' to exclude from the generated PKGBUILD file.')
- parser.add_option('--python-version', metavar='python_version', default='',
- help='Python version that will be used. Accepted values are'
- ' 2.7 or 3. Note that Python 3 is only supported in Indigo '
- 'and Jade.')
- 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('-r','--recursive', dest='recursive',
- action='store_true', default=False,
- help='Recursively import dependencies')
- parser.add_option('-u','--update', dest='update',
- action='store_true', default=False,
- help='Update PKGBUILD if a newer version is found.')
- options, args = parser.parse_args()
-
- if options.distro == "fuerte" and options.distro_url == default_distro_url:
- # Use legagy fuerte URL
- options.distro_url = 'https://raw.github.com/ros/rosdistro/master/releases/%s.yaml'
-
- # Dictionary containing valid Python versions
- valid_python_versions = {"fuerte": ["2.7"],
- "groovy": ["2.7"],
- "hydro": ["2.7"],
- "indigo": ["2.7", "3.4"],
- "jade": ["2.7", "3.4"]}
-
- # Default Python version that will be used
- default_python_version = {"fuerte": "2.7",
- "groovy": "2.7",
- "hydro": "2.7",
- "indigo": "2.7",
- "jade": "2.7"}
-
- python_version = default_python_version[options.distro]
- if options.python_version != "":
- if options.python_version in valid_python_versions[options.distro]:
- python_version = options.python_version
- else:
- print("Invalid Python version (%s) for %s, using version %s instead."
- % options.python_version % options.distro % python_version)
-
- distro = DistroDescription(options.distro,
- python_version=python_version,
- url=options.distro_url % options.distro)
-
- if options.output_directory:
- output_directory = os.path.expanduser(options.output_directory)
- if not os.path.exists(output_directory):
- os.makedirs(output_directory)
-
- if os.path.isdir(output_directory):
- distro_dir = os.path.abspath(output_directory)
- else:
- print("Invalid --output-directory. Exiting.")
- sys.exit()
- else:
- distro_dir = None
-
- if options.list_packages:
- list_packages(distro, distro_dir)
- return
- elif args:
- if not distro_dir:
- print("Missing mandatory --output-directory. Exiting.")
- sys.exit()
-
- generated = set()
-
- # Dump file containing the ordered list of packages to install
- distro_makepkg_filename = makepkg_filename % {'distro': options.distro}
- written = {"directory": distro_dir,
- "packages": list()}
-
- if os.path.isfile(distro_makepkg_filename):
- makepkg_dump = open(distro_makepkg_filename, "rb")
- written = pickle.load(makepkg_dump)
- makepkg_dump.close()
-
- # Dump file containing previously generated packages
- distro_generated_filename = updated_packages_filename % {'distro': options.distro}
-
- if os.path.isfile(distro_generated_filename):
- # Load dump of already updated packages to speedup updates
- print('Loading set of previously updated packages: %s'
- % (colored(distro_generated_filename, 'white',
- attrs=['bold'])))
- updated_packages_dump = open(distro_generated_filename, "rb")
- generated = pickle.load(updated_packages_dump)
- updated_packages_dump.close()
- for package in sorted(generated):
- print('Ignoring %s'
- % (colored(package, 'yellow', attrs=['bold'])))
-
- try:
- for package in args:
- generate_pkgbuild(distro, distro.package(package), distro_dir,
- exclude_dependencies=options.exclude_dependencies.split(','),
- force=options.force,
- no_overwrite=options.no_overwrite,
- update=options.update, recursive=options.recursive,
- rosdep_urls=options.rosdep_urls,
- generated=generated, written=written)
- except KeyboardInterrupt:
- pass
-
- if not os.path.exists(updates_packages_dir):
- os.makedirs(updates_packages_dir)
-
- makepkg_dump = open(distro_makepkg_filename, "wb")
- updated_packages_dump = open(distro_generated_filename, "wb")
- pickle.dump(generated, updated_packages_dump)
- pickle.dump(written, makepkg_dump)
- updated_packages_dump.close()
- makepkg_dump.close()
- else:
- parser.error('No package specified.')
-
-
-if __name__ == '__main__':
- main()