ros-infrastructure / rosdep

rosdep multi-package manager system dependency tool
http://ros.org/wiki/rosdep
BSD 3-Clause "New" or "Revised" License
75 stars 168 forks source link

Improve rosdep on Archlinux #560

Open hauptmech opened 6 years ago

hauptmech commented 6 years ago

This is a continuation of the discussion generated by #559.

To summarize: Arch has two installation methods; official binaries and community managed source (AUR) installs. Since Arch is a rolling release distro, it's common for application and library versions used by ROS to be no longer officially supported on Arch. Source (AUR) installs are necessary to provide these ROS dependencies. Furthermore, ROS itself is not officially supported on Arch, and is itself installed via AUR.

The expectation of Arch users is that AUR installs are an exception and should be done intentionally and only if you understand the consequences.

The rosdep database currently has AUR packages and trying to use rosdep when an AUR package is in the dependency chain (true for desktop and desktop-full source installs) will cause rosdep to error and do nothing. #559 proposed using an AUR installer to fix this.

Due to the difference between ROS releases and Arch releases, I don't think the rosdep database will be correct much of the time. However there is still benefit if rosdep can install as much as it can, leaving only a few packages to be installed by hand (or better yet, have database updates pushed to rosdistro).

I also think it's worth adding a package manager for AUR packages that can be invoked by users comfortable using AUR packages.

hauptmech commented 6 years ago

Modifying rosdep to install as many packages as it can, even if the database holds AUR packages or packages that are no longer supported can be done by using separate pacman commands for each package. (Note that one needs to add the -r flag to the rosdep command)

diff --git a/src/rosdep2/platforms/arch.py b/src/rosdep2/platforms/arch.py
index 8c1f676..2b27b13 100644
--- a/src/rosdep2/platforms/arch.py
+++ b/src/rosdep2/platforms/arch.py
@@ -69,4 +69,4 @@ class PacmanInstaller(PackageManagerInstaller):
         if quiet:
             command.append('-q')

-        return [self.elevate_priv(command + packages)]
+        return [self.elevate_priv(command + [package]) for package in packages]

The cost is a reduction in install speed. A more complex fix that checks rosdep database entries against pacman database entries in the pacman_detect function could improve this.

hauptmech commented 6 years ago

Adding a package manager for AUR would look something like the changes below. rosdep install uses pacman by default, but given an os override, will use the AUR pacage manager. For instance: rosdep install --os=arch:aur --from-paths src --ignore-src --rosdistro kinetic -r

The design of the rosdep yaml format requires an extra key for the version. Using 'aur' as I have is a little bit of a hack, but a reasonable one I think since Arch has no versions.

The command line given above will use yaourt interactively, giving the user the option to check the build scripts, which is the typical way it's used.

diff --git a/rosdep/base.yaml b/rosdep/base.yaml
index d46cb55eb..29c635d47 100644
--- a/rosdep/base.yaml
+++ b/rosdep/base.yaml
@@ -2128,7 +2128,9 @@ libogg:
   slackware: [libogg]
   ubuntu: [libogg-dev]
 libogre-dev:
-  arch: [ogre-1.9]
+  arch:
+    aur: 
+      yaourt: [ogre-1.9]
   debian:
     buster: [libogre-1.9-dev]
     jessie: [libogre-1.9-dev]
diff --git a/src/rosdep2/platforms/arch.py b/src/rosdep2/platforms/arch.py
index 8c1f676..0b5f282 100644
--- a/src/rosdep2/platforms/arch.py
+++ b/src/rosdep2/platforms/arch.py
@@ -30,19 +30,24 @@

 import subprocess

+from rospkg.os_detect import OS_DEBIAN, OS_LINARO, OS_UBUNTU, OS_ELEMENTARY, OsDetect
 from ..installers import PackageManagerInstaller
 from .source import SOURCE_INSTALLER

 ARCH_OS_NAME = 'arch'
 PACMAN_INSTALLER = 'pacman'
+AUR_INSTALLER = 'yaourt'

 def register_installers(context):
     context.set_installer(PACMAN_INSTALLER, PacmanInstaller())
+    context.set_installer(AUR_INSTALLER, AURInstaller())

 def register_platforms(context):
     context.add_os_installer_key(ARCH_OS_NAME, SOURCE_INSTALLER)
+    context.add_os_installer_key(ARCH_OS_NAME, AUR_INSTALLER)
     context.add_os_installer_key(ARCH_OS_NAME, PACMAN_INSTALLER)
     context.set_default_os_installer_key(ARCH_OS_NAME, lambda self: PACMAN_INSTALLER)
+    context.set_os_version_type(ARCH_OS_NAME, OsDetect.get_codename)

 def pacman_detect_single(p):
     return not subprocess.call(['pacman', '-T', p], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
@@ -69,4 +74,26 @@ class PacmanInstaller(PackageManagerInstaller):
         if quiet:
             command.append('-q')

-        return [self.elevate_priv(command + packages)]
+        return [self.elevate_priv(command + [package]) for package in packages]
+
+class AURInstaller(PackageManagerInstaller):
+
+    def __init__(self):
+        super(AURInstaller, self).__init__(pacman_detect)
+
+    def get_install_command(self, resolved, interactive=True, reinstall=False, quiet=False):
+        packages = self.get_packages_to_install(resolved, reinstall=reinstall)
+        if not packages:
+            return []
+
+        command  = ['yaourt', '-S']
+
+        if not interactive:
+            command.append('--noconfirm')
+        if not reinstall:
+            command.append('--needed')
+        if quiet:
+            command.append('-q')
+
+        return [command + [package] for package in packages]
+
hauptmech commented 6 years ago

@zootboy Suggested forcing the user to add their preferred aur-helper and leaving it blank/broken until then as an extra measure (above needing to explicitly specify the arch:aur package manager on the command line).

I don't see a good way to pass this through rosdep, but one could use a dummy script rosdep-aur-helper and leave it to the user to create a softlink on the PATH to their aur helper of choice.

patrickelectric commented 6 years ago

@hauptmech, thanks, your patch is great! I'll try to test this today. For me this PR, if applied, can overwrite #559 proposal.