Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add V2 Ruby plugin #3511

Open
wants to merge 10 commits into
base: main
Choose a base branch
from
1 change: 1 addition & 0 deletions snapcraft/plugins/v2/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,5 @@
from .npm import NpmPlugin # noqa: F401
from .python import PythonPlugin # noqa: F401
from .qmake import QMakePlugin # noqa: F401
from .ruby import RubyPlugin # noqa: F401
from .rust import RustPlugin # noqa: F401
156 changes: 156 additions & 0 deletions snapcraft/plugins/v2/ruby.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
# -*- Mode:Python; indent-tabs-mode:nil; tab-width:4 -*-
#
# Copyright (C) 2021 Patrik Wenger <[email protected]>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 3 as
# published by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.

"""The ruby plugin is useful for ruby based parts.
It uses ruby-install to install Ruby and can use bundler to install
dependencies from a `Gemfile` found in the sources.

Additionally, this plugin uses the following plugin-specific keywords:
- ruby-version:
(string)
The version of ruby you want this snap to run. (e.g. '3.0' or '2.7.2')
- ruby-flavor:
(string)
Other flavors of ruby supported by ruby-install (e.g. 'jruby', ...)
- gems:
(list)
A list of gems to install.
- use-bundler
(boolean)
Use bundler to install gems from a Gemfile (defaults 'false').
- use-jemalloc:
(boolean)
Build ruby with libjemalloc (defaults 'false').
- shared:
(boolean)
Build ruby as a shared library (defaults 'false').
- configure-options:
(array of strings)
Additional configure options to use when configuring ruby.
"""

import os
import re
import logging

from typing import Any, Dict, List, Set
from snapcraft.plugins.v2 import PluginV2


class RubyPlugin(PluginV2):
@classmethod
def get_schema(cls) -> Dict[str, Any]:
return {
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "object",
"additionalProperties": False,
"properties": {
"ruby-flavor": {
"type": "string",
"default": "ruby",
},
"ruby-version": {
"type": "string",
"default": "3.0",
"pattern": r"^\d+\.\d+(\.\d+)?$",
},
"use-bundler": {
paddor marked this conversation as resolved.
Show resolved Hide resolved
"type": "boolean",
"default": False,
},
"use-jemalloc": {
"type": "boolean",
"default": False,
},
"shared": {
"type": "boolean",
"default": False,
},
"configure-options": {
"type": "array",
"items": {"type": "string"},
"default": [],
},
"gems": {
"type": "array",
"items": {"type": "string"},
"default": [],
},
},
}

def get_build_snaps(self) -> Set[str]:
return set()

def get_build_packages(self) -> Set[str]:
packages = {"curl", "jq"}

if self.options.use_jemalloc:
packages.add("libjemalloc-dev")

return packages

def get_build_environment(self) -> Dict[str, str]:
env = {
"PATH": "${SNAPCRAFT_PART_INSTALL}/bin:${PATH}",
}

if self.options.shared:
# for finding ruby.so when running `gem` or `bundle`
env["LD_LIBRARY_PATH"] = "${SNAPCRAFT_PART_INSTALL}/lib:${LD_LIBRARY_PATH}"
paddor marked this conversation as resolved.
Show resolved Hide resolved

return env

def _configure_opts(self) -> List[str]:
configure_opts = [
"--without-baseruby",
"--enable-load-relative",
"--disable-install-doc",
] + self.options.configure_options

if self.options.shared:
configure_opts.append("--enable-shared")
if self.options.use_jemalloc:
configure_opts.append("--with-jemalloc")

return configure_opts

def _get_install_commands(self) -> List[str]:
paddor marked this conversation as resolved.
Show resolved Hide resolved
commands = []
commands.append("ruby_install_url=$(curl -L --proto '=https' --tlsv1.2 'https://api.github.com/repos/postmodern/ruby-install/tags' | jq -r '.[0].tarball_url')")
commands.append("curl -L --proto '=https' --tlsv1.2 $ruby_install_url | tar xz")
paddor marked this conversation as resolved.
Show resolved Hide resolved
commands.append("postmodern-ruby-install-*/bin/ruby-install -i ${{SNAPCRAFT_PART_INSTALL}} --package-manager apt -j${{SNAPCRAFT_PARALLEL_BUILD_COUNT}} {}-{} -- {}".format(
self.options.ruby_flavor,
self.options.ruby_version,
' '.join(self._configure_opts())))

# NOTE: Update bundler. Avoid conflicts/prompts about replacing bundler
# executables by removing them first.
commands.append("rm -f ${SNAPCRAFT_PART_INSTALL}/bin/{bundle,bundler}")
commands.append("gem install --env-shebang --no-document bundler")

if self.options.use_bundler:
commands.append("bundle")

if self.options.gems:
commands.append("gem install --env-shebang --no-document {}".format(' '.join(self.options.gems)))

return commands

def get_build_commands(self) -> List[str]:
commands = []
commands.extend(self._get_install_commands())
return commands