diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml new file mode 100644 index 00000000..2333bc3f --- /dev/null +++ b/.github/workflows/tests.yaml @@ -0,0 +1,25 @@ +name: Tests + +on: + push: + branches: + - main + pull_request: + branches: + - main + +jobs: + test-suite: + name: "Test Suite" + + runs-on: ubuntu-latest + + strategy: + fail-fast: false # Don't cancel all jobs if one fails. + + steps: + - uses: actions/checkout@v3 + - name: Run Setup + run: cd ${{ github.workspace }} && bin/setup + - name: Run Bazel Tests + run: cd ${{ github.workspace }} && bin/test-suite diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 00000000..f7f24c15 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,33 @@ +# How to Contribute + +This repository is currently a WIP, forked from +[rules_ruby](https://github.com/bazelruby/rules_ruby) for use in building and +testing Ruby [Protobuf](https://github.com/protocolbuffers/protobuf). + +We'd love to accept your patches and contributions to this project. There are +just a few small guidelines you need to follow. + +## Contributor License Agreement + +Contributions to this project must be accompanied by a Contributor License +Agreement (CLA). You (or your employer) retain the copyright to your +contribution; this simply gives us permission to use and redistribute your +contributions as part of the project. Head over to + to see your current agreements on file or +to sign a new one. + +You generally only need to submit a CLA once, so if you've already submitted one +(even if it was for a different project), you probably don't need to do it +again. + +## Code Reviews + +All submissions, including submissions by project members, require review. We +use GitHub pull requests for this purpose. Consult +[GitHub Help](https://help.github.com/articles/about-pull-requests/) for more +information on using pull requests. + +## Community Guidelines + +This project follows +[Google's Open Source Community Guidelines](https://opensource.google/conduct/). diff --git a/Gemfile.lock b/Gemfile.lock index 92438240..a5bc485b 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -7,7 +7,8 @@ GEM ast (~> 2.4.1) rainbow (3.0.0) regexp_parser (2.1.1) - rexml (3.2.5) + rexml (3.3.6) + strscan rubocop (0.93.1) parallel (~> 1.10) parser (>= 2.7.1.5) @@ -20,6 +21,7 @@ GEM rubocop-ast (1.11.0) parser (>= 3.0.1.1) ruby-progressbar (1.11.0) + strscan (3.1.0) unicode-display_width (1.8.0) PLATFORMS diff --git a/README.adoc b/README.adoc index 758e9bb0..1db3c555 100644 --- a/README.adoc +++ b/README.adoc @@ -92,17 +92,12 @@ load("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository") #——————————————————————————————————————————————————————————————————————— git_repository( - name = "bazelruby_rules_ruby", + name = "rules_ruby", remote = "https://github.com/bazelruby/rules_ruby.git", branch = "master" ) -load( - "@bazelruby_rules_ruby//ruby:deps.bzl", - "rules_ruby_dependencies", - "rules_ruby_select_sdk", -) - +load("@rules_ruby//ruby:deps.bzl", "rules_ruby_dependencies") rules_ruby_dependencies() #——————————————————————————————————————————————————————————————————————— @@ -113,16 +108,14 @@ rules_ruby_dependencies() load("@bazel_skylib//:workspace.bzl", "bazel_skylib_workspace") bazel_skylib_workspace() -rules_ruby_select_sdk(version = "3.0.2") +load("@rules_ruby//ruby:deps.bzl", "register_toolchain") +register_toolchains("ruby-3.0") #——————————————————————————————————————————————————————————————————————— # Now, load the ruby_bundle rule & install gems specified in the Gemfile #——————————————————————————————————————————————————————————————————————— -load( - "@bazelruby_rules_ruby//ruby:defs.bzl", - "ruby_bundle", -) +load("@ruby-3.0//:bundle.bzl", "ruby_bundle") ruby_bundle( name = "bundle", @@ -170,7 +163,7 @@ Add `ruby_library`, `ruby_binary`, `ruby_rspec` or `ruby_test` into your `BUILD. #——————————————————————————————————————————————————————————————————————— load( - "@bazelruby_rules_ruby//ruby:defs.bzl", + "@rules_ruby//ruby:defs.bzl", "ruby_binary", "ruby_library", "ruby_test", @@ -215,7 +208,7 @@ Use `ruby_gem` rule to package any number of ruby files or folders into a Ruby-G [source,python] ---- load( - "@bazelruby_rules_ruby//ruby:defs.bzl", + "@rules_ruby//ruby:defs.bzl", "ruby_gem", ) @@ -486,8 +479,7 @@ ruby_bundle( excludes = {}, srcs = [], vendor_cache = False, - ruby_sdk = "@org_ruby_lang_ruby_toolchain", - ruby_interpreter = "@org_ruby_lang_ruby_toolchain//:ruby", + ruby_interpreter = "@rules_ruby//ruby/runtime:interpreter", ) ---- @@ -555,7 +547,7 @@ List of glob patterns per gem to be excluded from the library. Keys are the name [source,python] ---- -load("@bazelruby_rules_ruby//ruby:defs.bzl", "ruby_bundle") +load("@ruby-3.0//:bundle.bzl", "ruby_bundle") ruby_bundle( name = "gems", @@ -572,7 +564,7 @@ your workspace. The name should match the name of the bundle. [source,python] ---- -load("@bazelruby_rules_ruby//ruby:defs.bzl", "ruby_bundle") +load("@ruby-3.0//:bundle.bzl", "ruby_bundle") workspace( name = "my_wksp", diff --git a/WORKSPACE b/WORKSPACE index e08c5ee3..6a1b9517 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -1,6 +1,6 @@ -workspace(name = "bazelruby_rules_ruby") +workspace(name = "rules_ruby") -load("@//ruby:deps.bzl", "rules_ruby_dependencies", "rules_ruby_select_sdk") +load("@//ruby:deps.bzl", "rules_ruby_dependencies") rules_ruby_dependencies() @@ -12,15 +12,36 @@ load("@bazel_skylib//lib:versions.bzl", "versions") versions.check("3.4.1") -rules_ruby_select_sdk("3.0.2") +load("@rules_ruby//ruby:defs.bzl", "ruby_runtime") + +# Register the system ruby version with a custom name. +ruby_runtime( + name = "system_ruby_custom", + version = "system", +) + +register_toolchains("@system_ruby_custom//:toolchain") + +# Register a versioned ruby with a custom name. +ruby_runtime( + name = "ruby3", + version = "ruby-3.0", +) + +register_toolchains("@ruby3//:toolchain") + +# Register a versioned ruby with its default name. +ruby_runtime("jruby-9.4") + +register_toolchains("@jruby-9.4//:toolchain") local_repository( - name = "bazelruby_rules_ruby_ruby_tests_testdata_another_workspace", + name = "rules_ruby_ruby_tests_testdata_another_workspace", path = "ruby/tests/testdata/another_workspace", ) local_repository( - name = "bazelruby_rules_ruby_ruby_tests_testdata_bundle_includes_workspace", + name = "rules_ruby_ruby_tests_testdata_bundle_includes_workspace", path = "ruby/tests/testdata/bundle_includes_workspace", ) @@ -95,11 +116,11 @@ container_pull( repository = "library/ruby", ) -load("@bazelruby_rules_ruby//ruby:defs.bzl", "ruby_bundle") +load("@system_ruby_custom//:bundle.bzl", "ruby_bundle") ruby_bundle( name = "bundle", - bundler_version = "2.1.4", + bundler_version = "2.4.22", excludes = { "mini_portile": ["test/**/*"], }, diff --git a/bin/deps b/bin/deps index dfdbbccd..00ffdd40 100755 --- a/bin/deps +++ b/bin/deps @@ -10,8 +10,9 @@ # ————————————————————————————————————————————————————————————————————————————————————— +export BASHMATIC_OS="$(uname -s | tr '[:upper:]' '[:lower:]')" [[ -z ${BASHMATIC_HOME} ]] && export BASHMATIC_HOME="${HOME}/.bashmatic" -[[ -d ${BASHMATIC_HOME} ]] || bash -c "$(curl -fsSL https://bashmatic.re1.re); bashmatic-install -q" +[[ -d ${BASHMATIC_HOME} ]] || bash -c "$(curl -fsSL https://raw.githubusercontent.com/kigster/bashmatic/master/bin/bashmatic-install); bashmatic-install -v -f -b v2.7.2" # shellcheck disable=SC1090 source "${BASHMATIC_HOME}/init.sh" 1>/dev/null 2>&1 diff --git a/bin/setup b/bin/setup index c0799cad..8875e278 100755 --- a/bin/setup +++ b/bin/setup @@ -37,7 +37,7 @@ setup.rbenv() { local installed_version="$(ruby -e 'puts RUBY_VERSION' | tr -d '\n')" if [[ ${installed_version} == ${ruby_version} ]]; then info "RUBY already installed, current version: ${bldylw}${ruby_version}" - return 0 + info "Setting up rbenv anyway" fi fi diff --git a/bin/test-suite b/bin/test-suite index 63643f16..bb435415 100755 --- a/bin/test-suite +++ b/bin/test-suite @@ -32,11 +32,6 @@ export BashMatic__Expr=" [[ -f ${HOME}/.bashmatic/init.sh ]] && source ${HOME}/.bashmatic/init.sh; set -e " -export Bazel__BuildSteps=" - bazel ${BAZEL_OPTS} info; echo; echo - bazel ${BAZEL_OPTS} build ${BAZEL_BUILD_OPTS} -- //... ; echo; echo - bazel ${BAZEL_OPTS} test ${BAZEL_BUILD_OPTS} ${BAZEL_TEST_OPTS} -- //... ; echo; echo -" deps.start-clock run.set-all abort-on-error show-output-on @@ -160,11 +155,15 @@ test.buildifier() { # Builds and runs workspace inside examples/simple_script test.simple-script() { + # This workspace requires a version specification + local RUBY_VERSION="--@rules_ruby//ruby/runtime:version=ruby-3.0 " __test.exec simple-script " cd examples/simple_script - ${Bazel__BuildSteps} - echo run :bin; bazel ${BAZEL_OPTS} run ${BAZEL_BUILD_OPTS} :bin - echo run :rubocop; bazel ${BAZEL_OPTS} run ${BAZEL_BUILD_OPTS} :rubocop + bazel ${BAZEL_OPTS} info; echo; echo + bazel ${BAZEL_OPTS} build ${BAZEL_BASE_BUILD_OPTS} ${RUBY_VERSION} -- //... ; echo; echo + bazel ${BAZEL_OPTS} test ${BAZEL_BASE_BUILD_OPTS} ${BAZEL_TEST_OPTS} ${RUBY_VERSION} -- //... ; echo; echo + echo run :bin; bazel ${BAZEL_OPTS} run ${BAZEL_BASE_BUILD_OPTS} ${RUBY_VERSION} :bin + echo run :rubocop; bazel ${BAZEL_OPTS} run ${BAZEL_BASE_BUILD_OPTS} ${RUBY_VERSION} :rubocop " } @@ -172,12 +171,21 @@ test.simple-script() { test.example-gem() { __test.exec example-gem " cd examples/example_gem - echo bazel ${BAZEL_OPTS} build ...:all; bazel ${BAZEL_OPTS} build ...:all + echo bazel ${BAZEL_OPTS} build ...:all + bazel ${BAZEL_OPTS} build --@rules_ruby//ruby/runtime:version=ruby-3.0 ...:all " } test.workspace() { - __test.exec workspace "${Bazel__BuildSteps}" + __test.exec workspace " + bazel ${BAZEL_OPTS} info; echo; echo + bazel ${BAZEL_OPTS} build ${BAZEL_BUILD_OPTS} -- //... ; echo; echo + bazel ${BAZEL_OPTS} test ${BAZEL_BUILD_OPTS} ${BAZEL_TEST_OPTS} -- //... ; echo; echo + bazel ${BAZEL_OPTS} build ${BAZEL_BUILD_OPTS} --@rules_ruby//ruby/runtime:version=ruby-3.0 -- //... ; echo; echo + bazel ${BAZEL_OPTS} test ${BAZEL_BUILD_OPTS} --@rules_ruby//ruby/runtime:version=ruby-3.0 ${BAZEL_TEST_OPTS} -- //... ; echo; echo + bazel ${BAZEL_OPTS} build ${BAZEL_BUILD_OPTS} --@rules_ruby//ruby/runtime:version=jruby-9.4 -- //... ; echo; echo + bazel ${BAZEL_OPTS} test ${BAZEL_BUILD_OPTS} --@rules_ruby//ruby/runtime:version=jruby-9.4 ${BAZEL_TEST_OPTS} -- //... ; echo; echo + " } # Private diff --git a/examples/example_gem/BUILD.bazel b/examples/example_gem/BUILD.bazel index 55948ee0..9b7baf6c 100644 --- a/examples/example_gem/BUILD.bazel +++ b/examples/example_gem/BUILD.bazel @@ -1,5 +1,5 @@ load( - "@bazelruby_rules_ruby//ruby:defs.bzl", + "@rules_ruby//ruby:defs.bzl", "ruby_gem", ) diff --git a/examples/example_gem/WORKSPACE b/examples/example_gem/WORKSPACE index 0f096a77..150de3b2 100644 --- a/examples/example_gem/WORKSPACE +++ b/examples/example_gem/WORKSPACE @@ -1,21 +1,21 @@ -workspace(name = "bazelruby_rules_ruby_example_gem") +workspace(name = "rules_ruby_example_gem") # Importing rules_ruby from the parent directory for developing # rules_ruby itself... local_repository( - name = "bazelruby_rules_ruby", + name = "rules_ruby", path = "../..", ) -load( - "@bazelruby_rules_ruby//ruby:deps.bzl", - "rules_ruby_dependencies", - "rules_ruby_select_sdk", -) +load("@rules_ruby//ruby:deps.bzl", "rules_ruby_dependencies") rules_ruby_dependencies() -rules_ruby_select_sdk("3.0.2") +load("@rules_ruby//ruby:defs.bzl", "ruby_runtime") + +ruby_runtime("ruby-3.0") + +register_toolchains("@ruby-3.0//:toolchain") load("@bazel_skylib//:workspace.bzl", "bazel_skylib_workspace") diff --git a/examples/example_gem/lib/BUILD b/examples/example_gem/lib/BUILD index 32394529..360c4c24 100644 --- a/examples/example_gem/lib/BUILD +++ b/examples/example_gem/lib/BUILD @@ -1,5 +1,5 @@ load( - "@bazelruby_rules_ruby//ruby:defs.bzl", + "@rules_ruby//ruby:defs.bzl", "ruby_library", ) diff --git a/examples/example_gem/lib/foo/BUILD b/examples/example_gem/lib/foo/BUILD index 9e6e2fe3..65ad9e78 100644 --- a/examples/example_gem/lib/foo/BUILD +++ b/examples/example_gem/lib/foo/BUILD @@ -1,5 +1,5 @@ load( - "@bazelruby_rules_ruby//ruby:defs.bzl", + "@rules_ruby//ruby:defs.bzl", "ruby_library", ) diff --git a/examples/simple_rails_api/BUILD b/examples/simple_rails_api/BUILD index c53e54b5..84815920 100644 --- a/examples/simple_rails_api/BUILD +++ b/examples/simple_rails_api/BUILD @@ -1,5 +1,5 @@ load( - "@bazelruby_rules_ruby//ruby:defs.bzl", + "@rules_ruby//ruby:defs.bzl", "ruby_binary", ) diff --git a/examples/simple_rails_api/Gemfile b/examples/simple_rails_api/Gemfile index 3fab5dae..385b769d 100644 --- a/examples/simple_rails_api/Gemfile +++ b/examples/simple_rails_api/Gemfile @@ -2,11 +2,11 @@ source 'https://rubygems.org' git_source(:github) { |repo| "https://github.com/#{repo}.git" } # Bundle edge Rails instead: gem 'rails', github: 'rails/rails' -gem 'rails', '~> 6.0.2' +gem 'rails', '~> 6.1.7' # Use sqlite3 as the database for Active Record gem 'sqlite3', '~> 1.4' # Use Puma as the app server -gem 'puma', '~> 4.3' +gem 'puma', '~> 5.6' # Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder # gem 'jbuilder', '~> 2.7' # Use Redis adapter to run Action Cable in production diff --git a/examples/simple_rails_api/Gemfile.lock b/examples/simple_rails_api/Gemfile.lock index 9da3cb42..4e78dc36 100644 --- a/examples/simple_rails_api/Gemfile.lock +++ b/examples/simple_rails_api/Gemfile.lock @@ -1,124 +1,143 @@ GEM remote: https://rubygems.org/ specs: - actioncable (6.0.4.1) - actionpack (= 6.0.4.1) + actioncable (6.1.7.8) + actionpack (= 6.1.7.8) + activesupport (= 6.1.7.8) nio4r (~> 2.0) websocket-driver (>= 0.6.1) - actionmailbox (6.0.4.1) - actionpack (= 6.0.4.1) - activejob (= 6.0.4.1) - activerecord (= 6.0.4.1) - activestorage (= 6.0.4.1) - activesupport (= 6.0.4.1) + actionmailbox (6.1.7.8) + actionpack (= 6.1.7.8) + activejob (= 6.1.7.8) + activerecord (= 6.1.7.8) + activestorage (= 6.1.7.8) + activesupport (= 6.1.7.8) mail (>= 2.7.1) - actionmailer (6.0.4.1) - actionpack (= 6.0.4.1) - actionview (= 6.0.4.1) - activejob (= 6.0.4.1) + actionmailer (6.1.7.8) + actionpack (= 6.1.7.8) + actionview (= 6.1.7.8) + activejob (= 6.1.7.8) + activesupport (= 6.1.7.8) mail (~> 2.5, >= 2.5.4) rails-dom-testing (~> 2.0) - actionpack (6.0.4.1) - actionview (= 6.0.4.1) - activesupport (= 6.0.4.1) - rack (~> 2.0, >= 2.0.8) + actionpack (6.1.7.8) + actionview (= 6.1.7.8) + activesupport (= 6.1.7.8) + rack (~> 2.0, >= 2.0.9) rack-test (>= 0.6.3) rails-dom-testing (~> 2.0) rails-html-sanitizer (~> 1.0, >= 1.2.0) - actiontext (6.0.4.1) - actionpack (= 6.0.4.1) - activerecord (= 6.0.4.1) - activestorage (= 6.0.4.1) - activesupport (= 6.0.4.1) + actiontext (6.1.7.8) + actionpack (= 6.1.7.8) + activerecord (= 6.1.7.8) + activestorage (= 6.1.7.8) + activesupport (= 6.1.7.8) nokogiri (>= 1.8.5) - actionview (6.0.4.1) - activesupport (= 6.0.4.1) + actionview (6.1.7.8) + activesupport (= 6.1.7.8) builder (~> 3.1) erubi (~> 1.4) rails-dom-testing (~> 2.0) rails-html-sanitizer (~> 1.1, >= 1.2.0) - activejob (6.0.4.1) - activesupport (= 6.0.4.1) + activejob (6.1.7.8) + activesupport (= 6.1.7.8) globalid (>= 0.3.6) - activemodel (6.0.4.1) - activesupport (= 6.0.4.1) - activerecord (6.0.4.1) - activemodel (= 6.0.4.1) - activesupport (= 6.0.4.1) - activestorage (6.0.4.1) - actionpack (= 6.0.4.1) - activejob (= 6.0.4.1) - activerecord (= 6.0.4.1) - marcel (~> 1.0.0) - activesupport (6.0.4.1) + activemodel (6.1.7.8) + activesupport (= 6.1.7.8) + activerecord (6.1.7.8) + activemodel (= 6.1.7.8) + activesupport (= 6.1.7.8) + activestorage (6.1.7.8) + actionpack (= 6.1.7.8) + activejob (= 6.1.7.8) + activerecord (= 6.1.7.8) + activesupport (= 6.1.7.8) + marcel (~> 1.0) + mini_mime (>= 1.1.0) + activesupport (6.1.7.8) concurrent-ruby (~> 1.0, >= 1.0.2) - i18n (>= 0.7, < 2) - minitest (~> 5.1) - tzinfo (~> 1.1) - zeitwerk (~> 2.2, >= 2.2.2) + i18n (>= 1.6, < 2) + minitest (>= 5.1) + tzinfo (~> 2.0) + zeitwerk (~> 2.3) bootsnap (1.9.1) msgpack (~> 1.0) - builder (3.2.4) + builder (3.3.0) byebug (11.1.3) - concurrent-ruby (1.1.9) + concurrent-ruby (1.3.4) crass (1.0.6) - erubi (1.10.0) + date (3.3.4) + erubi (1.13.0) ffi (1.15.4) - globalid (0.5.2) - activesupport (>= 5.0) - i18n (1.8.10) + globalid (1.2.1) + activesupport (>= 6.1) + i18n (1.14.6) concurrent-ruby (~> 1.0) listen (3.0.8) rb-fsevent (~> 0.9, >= 0.9.4) rb-inotify (~> 0.9, >= 0.9.7) - loofah (2.12.0) + loofah (2.22.0) crass (~> 1.0.2) - nokogiri (>= 1.5.9) - mail (2.7.1) + nokogiri (>= 1.12.0) + mail (2.8.1) mini_mime (>= 0.1.1) - marcel (1.0.2) - method_source (1.0.0) - mini_mime (1.1.1) - mini_portile2 (2.8.0) - minitest (5.14.4) + net-imap + net-pop + net-smtp + marcel (1.0.4) + method_source (1.1.0) + mini_mime (1.1.5) + mini_portile2 (2.8.7) + minitest (5.25.1) msgpack (1.4.2) - nio4r (2.5.8) - nokogiri (1.13.4) - mini_portile2 (~> 2.8.0) + net-imap (0.4.16) + date + net-protocol + net-pop (0.1.2) + net-protocol + net-protocol (0.2.2) + timeout + net-smtp (0.5.0) + net-protocol + nio4r (2.7.3) + nokogiri (1.16.7) + mini_portile2 (~> 2.8.2) racc (~> 1.4) - puma (4.3.12) + puma (5.6.9) nio4r (~> 2.0) - racc (1.6.0) - rack (2.2.3) - rack-test (1.1.0) - rack (>= 1.0, < 3) - rails (6.0.4.1) - actioncable (= 6.0.4.1) - actionmailbox (= 6.0.4.1) - actionmailer (= 6.0.4.1) - actionpack (= 6.0.4.1) - actiontext (= 6.0.4.1) - actionview (= 6.0.4.1) - activejob (= 6.0.4.1) - activemodel (= 6.0.4.1) - activerecord (= 6.0.4.1) - activestorage (= 6.0.4.1) - activesupport (= 6.0.4.1) - bundler (>= 1.3.0) - railties (= 6.0.4.1) + racc (1.8.1) + rack (2.2.9) + rack-test (2.1.0) + rack (>= 1.3) + rails (6.1.7.8) + actioncable (= 6.1.7.8) + actionmailbox (= 6.1.7.8) + actionmailer (= 6.1.7.8) + actionpack (= 6.1.7.8) + actiontext (= 6.1.7.8) + actionview (= 6.1.7.8) + activejob (= 6.1.7.8) + activemodel (= 6.1.7.8) + activerecord (= 6.1.7.8) + activestorage (= 6.1.7.8) + activesupport (= 6.1.7.8) + bundler (>= 1.15.0) + railties (= 6.1.7.8) sprockets-rails (>= 2.0.0) - rails-dom-testing (2.0.3) - activesupport (>= 4.2.0) + rails-dom-testing (2.2.0) + activesupport (>= 5.0.0) + minitest nokogiri (>= 1.6) - rails-html-sanitizer (1.4.2) - loofah (~> 2.3) - railties (6.0.4.1) - actionpack (= 6.0.4.1) - activesupport (= 6.0.4.1) + rails-html-sanitizer (1.6.0) + loofah (~> 2.21) + nokogiri (~> 1.14) + railties (6.1.7.8) + actionpack (= 6.1.7.8) + activesupport (= 6.1.7.8) method_source - rake (>= 0.8.7) - thor (>= 0.20.3, < 2.0) - rake (13.0.6) + rake (>= 12.2) + thor (~> 1.0) + rake (13.2.1) rb-fsevent (0.11.0) rb-inotify (0.10.1) ffi (~> 1.0) @@ -126,22 +145,22 @@ GEM spring-watcher-listen (2.0.1) listen (>= 2.7, < 4.0) spring (>= 1.2, < 3.0) - sprockets (4.0.2) + sprockets (4.2.1) concurrent-ruby (~> 1.0) - rack (> 1, < 3) - sprockets-rails (3.2.2) - actionpack (>= 4.0) - activesupport (>= 4.0) + rack (>= 2.2.4, < 4) + sprockets-rails (3.5.2) + actionpack (>= 6.1) + activesupport (>= 6.1) sprockets (>= 3.0.0) sqlite3 (1.4.2) - thor (1.1.0) - thread_safe (0.3.6) - tzinfo (1.2.9) - thread_safe (~> 0.1) - websocket-driver (0.7.5) + thor (1.3.2) + timeout (0.4.1) + tzinfo (2.0.6) + concurrent-ruby (~> 1.0) + websocket-driver (0.7.6) websocket-extensions (>= 0.1.0) websocket-extensions (0.1.5) - zeitwerk (2.4.2) + zeitwerk (2.7.0) PLATFORMS ruby @@ -150,8 +169,8 @@ DEPENDENCIES bootsnap (>= 1.4.2) byebug listen (>= 3.0.5, < 3.2) - puma (~> 4.3) - rails (~> 6.0.2) + puma (~> 5.6) + rails (~> 6.1.7) spring spring-watcher-listen (~> 2.0.0) sqlite3 (~> 1.4) diff --git a/examples/simple_rails_api/WORKSPACE b/examples/simple_rails_api/WORKSPACE index 8585cfec..287c06b4 100644 --- a/examples/simple_rails_api/WORKSPACE +++ b/examples/simple_rails_api/WORKSPACE @@ -1,27 +1,27 @@ -workspace(name = "bazelruby_rules_ruby_example") +workspace(name = "rules_ruby_example") # Importing rules_ruby from the parent directory for developing # rules_ruby itself... local_repository( - name = "bazelruby_rules_ruby", + name = "rules_ruby", path = "../..", ) -load( - "@bazelruby_rules_ruby//ruby:deps.bzl", - "rules_ruby_dependencies", - "rules_ruby_select_sdk", -) +load("@rules_ruby//ruby:deps.bzl", "rules_ruby_dependencies") rules_ruby_dependencies() -rules_ruby_select_sdk(version = "3.0.2") +load("@rules_ruby//ruby:defs.bzl", "ruby_runtime") + +ruby_runtime("ruby-3.0") + +register_toolchains("@ruby-3.0//:toolchain") load("@bazel_skylib//:workspace.bzl", "bazel_skylib_workspace") bazel_skylib_workspace() -load("@bazelruby_rules_ruby//ruby:defs.bzl", "ruby_bundle") +load("@workspace_ruby//:bundle.bzl", "ruby_bundle") ruby_bundle( name = "bundle", diff --git a/examples/simple_script/BUILD.bazel b/examples/simple_script/BUILD.bazel index 3f81e7b9..678c6497 100644 --- a/examples/simple_script/BUILD.bazel +++ b/examples/simple_script/BUILD.bazel @@ -1,5 +1,5 @@ load( - "@bazelruby_rules_ruby//ruby:defs.bzl", + "@rules_ruby//ruby:defs.bzl", "ruby_binary", "ruby_rspec", "ruby_rubocop", diff --git a/examples/simple_script/Gemfile.lock b/examples/simple_script/Gemfile.lock index 002c1270..9c0f9eff 100644 --- a/examples/simple_script/Gemfile.lock +++ b/examples/simple_script/Gemfile.lock @@ -10,7 +10,8 @@ GEM ast (~> 2.4.1) rainbow (3.0.0) regexp_parser (2.1.1) - rexml (3.2.5) + rexml (3.3.3) + strscan rspec (3.7.0) rspec-core (~> 3.7.0) rspec-expectations (~> 3.7.0) @@ -39,6 +40,7 @@ GEM rubocop-ast (1.11.0) parser (>= 3.0.1.1) ruby-progressbar (1.11.0) + strscan (3.1.0) unicode-display_width (2.1.0) PLATFORMS diff --git a/examples/simple_script/WORKSPACE b/examples/simple_script/WORKSPACE index 4ad11d15..85346469 100644 --- a/examples/simple_script/WORKSPACE +++ b/examples/simple_script/WORKSPACE @@ -1,23 +1,23 @@ -workspace(name = "bazelruby_rules_ruby_example") +workspace(name = "rules_ruby_example") # Importing rules_ruby from the parent directory for developing # rules_ruby itself... local_repository( - name = "bazelruby_rules_ruby", + name = "rules_ruby", path = "../..", ) -load( - "@bazelruby_rules_ruby//ruby:deps.bzl", - "rules_ruby_dependencies", - "rules_ruby_select_sdk", -) +load("@rules_ruby//ruby:deps.bzl", "rules_ruby_dependencies") rules_ruby_dependencies() -rules_ruby_select_sdk(version = "3.0.2") +load("@rules_ruby//ruby:defs.bzl", "ruby_runtime") + +ruby_runtime("ruby-3.0") + +register_toolchains("@ruby-3.0//:toolchain") -load("@bazelruby_rules_ruby//ruby:defs.bzl", "ruby_bundle") +load("@ruby-3.0//:bundle.bzl", "ruby_bundle") ruby_bundle( name = "bundle", diff --git a/examples/simple_script/lib/BUILD b/examples/simple_script/lib/BUILD index f125ff86..b212e7f6 100644 --- a/examples/simple_script/lib/BUILD +++ b/examples/simple_script/lib/BUILD @@ -1,5 +1,5 @@ load( - "@bazelruby_rules_ruby//ruby:defs.bzl", + "@rules_ruby//ruby:defs.bzl", "ruby_library", ) diff --git a/examples/simple_script_vendored/BUILD.bazel b/examples/simple_script_vendored/BUILD.bazel index 1fc2d136..43b72f7e 100644 --- a/examples/simple_script_vendored/BUILD.bazel +++ b/examples/simple_script_vendored/BUILD.bazel @@ -1,5 +1,5 @@ load( - "@bazelruby_rules_ruby//ruby:defs.bzl", + "@rules_ruby//ruby:defs.bzl", "ruby_binary", "ruby_rspec", "ruby_rubocop", diff --git a/examples/simple_script_vendored/Gemfile.lock b/examples/simple_script_vendored/Gemfile.lock index 315f6e68..bc9b5d3b 100644 --- a/examples/simple_script_vendored/Gemfile.lock +++ b/examples/simple_script_vendored/Gemfile.lock @@ -8,7 +8,8 @@ GEM ast (~> 2.4.1) rainbow (3.0.0) regexp_parser (2.1.1) - rexml (3.2.5) + rexml (3.3.6) + strscan rspec (3.7.0) rspec-core (~> 3.7.0) rspec-expectations (~> 3.7.0) @@ -37,6 +38,7 @@ GEM rubocop-ast (1.11.0) parser (>= 3.0.1.1) ruby-progressbar (1.11.0) + strscan (3.1.0) unicode-display_width (2.1.0) PLATFORMS diff --git a/examples/simple_script_vendored/WORKSPACE b/examples/simple_script_vendored/WORKSPACE index 3aff264d..93609238 100644 --- a/examples/simple_script_vendored/WORKSPACE +++ b/examples/simple_script_vendored/WORKSPACE @@ -1,26 +1,29 @@ workspace( - name = "bazelruby_rules_ruby_example", + name = "rules_ruby_example", managed_directories = {"@bundle": ["vendor"]}, ) # Importing rules_ruby from the parent directory for developing # rules_ruby itself... local_repository( - name = "bazelruby_rules_ruby", + name = "rules_ruby", path = "../..", ) -load( - "@bazelruby_rules_ruby//ruby:deps.bzl", - "rules_ruby_dependencies", - "rules_ruby_select_sdk", -) +load("@rules_ruby//ruby:deps.bzl", "rules_ruby_dependencies") rules_ruby_dependencies() -rules_ruby_select_sdk(version = "2.7.1") +load("@rules_ruby//ruby:defs.bzl", "ruby_runtime") + +ruby_runtime( + name = "ruby-2.7", + version = "ruby-2.7.1", +) + +register_toolchains("@ruby-2.7//:toolchain") -load("@bazelruby_rules_ruby//ruby:defs.bzl", "ruby_bundle") +load("@ruby-2.7.1//:bundle.bzl", "ruby_bundle") ruby_bundle( name = "bundle", diff --git a/examples/simple_script_vendored/lib/BUILD b/examples/simple_script_vendored/lib/BUILD index f125ff86..b212e7f6 100644 --- a/examples/simple_script_vendored/lib/BUILD +++ b/examples/simple_script_vendored/lib/BUILD @@ -1,5 +1,5 @@ load( - "@bazelruby_rules_ruby//ruby:defs.bzl", + "@rules_ruby//ruby:defs.bzl", "ruby_library", ) diff --git a/examples/simple_script_vendored/vendor/cache/rexml-3.2.5.gem b/examples/simple_script_vendored/vendor/cache/rexml-3.2.5.gem deleted file mode 100644 index 5680fec4..00000000 Binary files a/examples/simple_script_vendored/vendor/cache/rexml-3.2.5.gem and /dev/null differ diff --git a/examples/simple_script_vendored/vendor/cache/rexml-3.3.6.gem b/examples/simple_script_vendored/vendor/cache/rexml-3.3.6.gem new file mode 100644 index 00000000..bf6b6fdb Binary files /dev/null and b/examples/simple_script_vendored/vendor/cache/rexml-3.3.6.gem differ diff --git a/examples/simple_script_vendored/vendor/cache/strscan-3.1.0.gem b/examples/simple_script_vendored/vendor/cache/strscan-3.1.0.gem new file mode 100644 index 00000000..e7bd7071 Binary files /dev/null and b/examples/simple_script_vendored/vendor/cache/strscan-3.1.0.gem differ diff --git a/ruby/defs.bzl b/ruby/defs.bzl index 1777d38d..924ac2a1 100644 --- a/ruby/defs.bzl +++ b/ruby/defs.bzl @@ -1,44 +1,49 @@ load( - "@bazelruby_rules_ruby//ruby/private:toolchain.bzl", + "@rules_ruby//ruby/private:toolchain.bzl", + _mock_toolchain = "mock_ruby_toolchain", _toolchain = "ruby_toolchain", ) load( - "@bazelruby_rules_ruby//ruby/private:library.bzl", + "@rules_ruby//ruby/private:library.bzl", _library = "ruby_library", ) load( - "@bazelruby_rules_ruby//ruby/private:binary.bzl", + "@rules_ruby//ruby/private:binary.bzl", _binary = "ruby_binary", _test = "ruby_test", ) load( - "@bazelruby_rules_ruby//ruby/private/bundle:def.bzl", - _bundle = "bundle_install", - _ruby_bundle = "ruby_bundle_install", + "@rules_ruby//ruby/private/bundle:def.bzl", + _bundle_install = "bundle_install", ) load( - "@bazelruby_rules_ruby//ruby/private:rspec.bzl", + "@rules_ruby//ruby/private:rspec.bzl", _rspec = "ruby_rspec", _rspec_test = "ruby_rspec_test", ) load( - "@bazelruby_rules_ruby//ruby/private/rubocop:def.bzl", + "@rules_ruby//ruby/private/rubocop:def.bzl", _rubocop = "rubocop", ) load( - "@bazelruby_rules_ruby//ruby/private/gemspec:def.bzl", + "@rules_ruby//ruby/private/gemspec:def.bzl", _gem = "gem", _gemspec = "gemspec", ) +load( + "@rules_ruby//ruby/private:sdk.bzl", + _register_ruby_runtime = "register_ruby_runtime", +) +ruby_mock_toolchain = _mock_toolchain ruby_toolchain = _toolchain ruby_library = _library ruby_binary = _binary ruby_test = _test ruby_rspec_test = _rspec_test ruby_rspec = _rspec -ruby_bundle = _ruby_bundle -ruby_bundle_install = _bundle +ruby_bundle_install = _bundle_install ruby_rubocop = _rubocop ruby_gemspec = _gemspec ruby_gem = _gem +ruby_runtime = _register_ruby_runtime diff --git a/ruby/deps.bzl b/ruby/deps.bzl index 3a7c45b7..90c53ace 100644 --- a/ruby/deps.bzl +++ b/ruby/deps.bzl @@ -1,12 +1,7 @@ # Repository rules load( - "@bazelruby_rules_ruby//ruby/private:dependencies.bzl", + "@rules_ruby//ruby/private:dependencies.bzl", _rules_ruby_dependencies = "rules_ruby_dependencies", ) -load( - "@bazelruby_rules_ruby//ruby/private:sdk.bzl", - _rules_ruby_select_sdk = "rules_ruby_select_sdk", -) rules_ruby_dependencies = _rules_ruby_dependencies -rules_ruby_select_sdk = _rules_ruby_select_sdk diff --git a/ruby/private/BUILD.bazel b/ruby/private/BUILD.bazel index 1c16e04c..98152bbb 100644 --- a/ruby/private/BUILD.bazel +++ b/ruby/private/BUILD.bazel @@ -1,6 +1,7 @@ exports_files( [ "binary_wrapper.tpl", + "binary_runner.tpl", ], visibility = ["//visibility:public"], ) diff --git a/ruby/private/binary.bzl b/ruby/private/binary.bzl index 4a38054d..480fe5e5 100644 --- a/ruby/private/binary.bzl +++ b/ruby/private/binary.bzl @@ -29,7 +29,9 @@ def _get_gem_path(incpaths): # to create a rule (eg, rubocop) that does exactly the same. def ruby_binary_macro(ctx, main, srcs): sdk = ctx.toolchains[TOOLCHAIN_TYPE_NAME].ruby_runtime - interpreter = sdk.interpreter[DefaultInfo].files_to_run.executable + interpreter_info = sdk.interpreter[DefaultInfo] + interpreter = interpreter_info.files_to_run.executable + interpreter_runfiles = interpreter_info.default_runfiles.merge(interpreter_info.data_runfiles) if not main: expected_name = "%s.rb" % ctx.attr.name @@ -45,10 +47,11 @@ def ruby_binary_macro(ctx, main, srcs): ) executable = ctx.actions.declare_file(ctx.attr.name) + wrapper = ctx.actions.declare_file(ctx.attr.name + "_wrapper") deps = _transitive_deps( ctx, - extra_files = [executable], + extra_files = [executable, wrapper, interpreter], extra_deps = ctx.attr._misc_deps, ) @@ -60,21 +63,34 @@ def ruby_binary_macro(ctx, main, srcs): ctx.actions.expand_template( template = ctx.file._wrapper_template, - output = executable, + output = wrapper, substitutions = { "{loadpaths}": repr(deps.incpaths.to_list()), "{rubyopt}": repr(rubyopt), "{main}": repr(_to_manifest_path(ctx, main)), - "{interpreter}": _to_manifest_path(ctx, interpreter), "{gem_path}": gem_path, "{should_gem_pristine}": str(len(gems_to_pristine) > 0).lower(), "{gems_to_pristine}": " ".join(gems_to_pristine), }, ) + ctx.actions.expand_template( + template = ctx.file._runner_template, + output = executable, + substitutions = { + "{main}": wrapper.short_path, + "{interpreter}": interpreter.short_path, + "{workspace_name}": ctx.label.workspace_name or ctx.workspace_name, + }, + is_executable = True, + ) + info = DefaultInfo( executable = executable, - runfiles = deps.default_files.merge(deps.data_files), + runfiles = deps.default_files + .merge(deps.data_files) + .merge(interpreter_runfiles) + .merge(ctx.runfiles(files = [wrapper])), ) return [info] diff --git a/ruby/private/binary_runner.tpl b/ruby/private/binary_runner.tpl new file mode 100644 index 00000000..dc5ae042 --- /dev/null +++ b/ruby/private/binary_runner.tpl @@ -0,0 +1,14 @@ +#!/bin/sh + +if [ -n "${RUNFILES_DIR+x}" ]; then + PATH_PREFIX=$RUNFILES_DIR/{workspace_name}/ +elif [ -s `dirname $0`/../../MANIFEST ]; then + PATH_PREFIX=`cd $(dirname $0); pwd`/ +elif [ -d $0.runfiles ]; then + PATH_PREFIX=`cd $0.runfiles; pwd`/{workspace_name}/ +else + echo "WARNING: it does not look to be at the .runfiles directory" >&2 + exit 1 +fi + +$PATH_PREFIX{interpreter} -I${PATH_PREFIX} ${PATH_PREFIX}{main} "$@" \ No newline at end of file diff --git a/ruby/private/binary_wrapper.tpl b/ruby/private/binary_wrapper.tpl index 09e04024..3b633621 100755 --- a/ruby/private/binary_wrapper.tpl +++ b/ruby/private/binary_wrapper.tpl @@ -1,5 +1,3 @@ -#!/usr/bin/env ruby - # Ruby-port of the Bazel's wrapper script for Python # Copyright 2017 The Bazel Authors. All rights reserved. diff --git a/ruby/private/bundle/create_bundle_build_file.rb b/ruby/private/bundle/create_bundle_build_file.rb index 52626cf2..dfa85960 100755 --- a/ruby/private/bundle/create_bundle_build_file.rb +++ b/ruby/private/bundle/create_bundle_build_file.rb @@ -68,7 +68,9 @@ # # Library path differs across implementations as `lib/ruby` on MRI and `lib/jruby` on JRuby. GEM_PATH = ->(ruby_version, gem_name, gem_version) do - Dir.glob("lib/#{RbConfig::CONFIG['RUBY_INSTALL_NAME']}/#{ruby_version}/gems/#{gem_name}-#{gem_version}*").first + glob = Dir.glob("lib/#{RbConfig::CONFIG['RUBY_BASE_NAME']}/#{ruby_version}/gems/#{gem_name}-#{gem_version}*").first + alt_glob = Dir.glob("lib/#{RbConfig::CONFIG['RUBY_BASE_NAME']}/#{ruby_version}/bundler/gems/#{gem_name}-*").first + glob || alt_glob end # For ordinary gems, this path is like 'lib/ruby/3.0.0/specifications/rspec-3.10.0.gemspec'. @@ -81,9 +83,13 @@ # # Library path differs across implementations as `lib/ruby` on MRI and `lib/jruby` on JRuby. SPEC_PATH = ->(ruby_version, gem_name, gem_version) do - Dir.glob("lib/#{RbConfig::CONFIG['RUBY_INSTALL_NAME']}/#{ruby_version}/specifications/#{gem_name}-#{gem_version}*.gemspec").first + glob = Dir.glob("lib/#{RbConfig::CONFIG['RUBY_BASE_NAME']}/#{ruby_version}/specifications/#{gem_name}-#{gem_version}*.gemspec").first + alt_glob = Dir.glob("lib/#{RbConfig::CONFIG['RUBY_BASE_NAME']}/#{ruby_version}/bundler/gems/#{gem_name}-*/**/*.gemspec").first + glob || alt_glob end +HERE = File.absolute_path '.' + require 'bundler' require 'json' require 'stringio' @@ -191,7 +197,18 @@ def initialize(workspace_name:, # This attribute returns 0 as the third minor version number, which happens to be # what Ruby uses in the PATH to gems, eg. ruby 2.6.5 would have a folder called # ruby/2.6.0/gems for all minor versions of 2.6.* - @ruby_version ||= (RUBY_VERSION.split('.')[0..1] << 0).join('.') + @ruby_version ||= begin + version_string = (RUBY_VERSION.split('.')[0..1] << 0).join('.') + if File.exist?("lib/#{RbConfig::CONFIG['RUBY_BASE_NAME']}/#{version_string}") + version_string + else + if File.exist?("lib/#{RbConfig::CONFIG['RUBY_BASE_NAME']}/#{version_string}+0") + version_string + "+0" + else + raise "Cannot find directory named #{version_string} within lib/#{RbConfig::CONFIG['RUBY_BASE_NAME']}" + end + end + end end def generate! @@ -261,7 +278,14 @@ def register_gem(spec, template_out, bundle_lib_paths, bundle_binaries) # Usually, registering the directory paths listed in the `require_paths` of gemspecs is sufficient, but # some gems also require additional paths to be included in the load paths. require_paths += include_array(spec.name) - gem_lib_paths = require_paths.map { |require_path| File.join(gem_path, require_path) } + gem_lib_paths = require_paths.map do |require_path| + # Gems with native extensions (like ffi) will sometimes have elements of + # require_paths that are absolute rather than gem-path relative paths. + # It is incorrect to prepend those paths with the gem_path and Bazel will + # only allow relative paths as inputs to its glob() function. + pathname = Pathname.new(require_path) + pathname.absolute? ? pathname.relative_path_from(HERE).to_s : File.join(gem_path, require_path) + end bundle_lib_paths.push(*gem_lib_paths) # paths to search for executables diff --git a/ruby/private/bundle/def.bzl b/ruby/private/bundle/def.bzl index e368bd4c..c289d0ae 100644 --- a/ruby/private/bundle/def.bzl +++ b/ruby/private/bundle/def.bzl @@ -44,7 +44,7 @@ def run_bundler(runtime_ctx, bundler_arguments, previous_result): # $ bundle config --local | --global config-option config-value # # @config_category can be either 'local' or 'global' -def set_bundler_config(runtime_ctx, previous_result, config_category = "local"): +def set_bundler_config(runtime_ctx, previous_result, has_lock = True, config_category = "local"): # Bundler is deprecating various flags in favor of the configuration. # HOWEVER — for reasons I can't explain, Bazel runs "bundle install" *prior* # to setting these flags. So the flags are then useless until we can force the @@ -53,11 +53,11 @@ def set_bundler_config(runtime_ctx, previous_result, config_category = "local"): # # Set local configuration options for bundler bundler_config = { - "deployment": "true", + "deployment": "true" if has_lock else "false", "standalone": "true", "force": "false", "redownload": "false", - "frozen": "true", + "frozen": "true" if has_lock else "false", "path": BUNDLE_PATH, "jobs": "20", "shebang": runtime_ctx.interpreter, @@ -117,11 +117,12 @@ def bundle_install(runtime_ctx, previous_result): cwd = runtime_ctx.ctx.path(".") bundler_args = [ "install", - "--binstubs={}".format(cwd.get_child(BUNDLE_BIN_PATH)), - "--path={}".format(cwd.get_child(BUNDLE_PATH)), + "-V", "--standalone", "--gemfile={}".format(runtime_ctx.ctx.attr.gemfile.name), + "--jobs=10", # run a few jobs to ensure no gem install is blocking another ] + if runtime_ctx.ctx.attr.gemfile_lock: bundler_args += ["--deployment", "--frozen"] @@ -133,8 +134,18 @@ def bundle_install(runtime_ctx, previous_result): if result.return_code: fail("bundle install failed: %s%s" % (result.stdout, result.stderr)) - else: - return result + + # Creates a directory and place any executables from the gem there. + result = run_bundler(runtime_ctx, [ + "binstubs", + "--all", + "--path", + "{}".format(BUNDLE_BIN_PATH), + ], previous_result) + if result.return_code: + fail("bundle binstubs failed: %s%s" % (result.stdout, result.stderr)) + + return result def generate_bundle_build_file(runtime_ctx, previous_result): if runtime_ctx.ctx.attr.gemfile_lock: @@ -162,7 +173,7 @@ def generate_bundle_build_file(runtime_ctx, previous_result): if result.return_code: fail("build file generation failed: %s%s" % (result.stdout, result.stderr)) -def _ruby_bundle_impl(ctx): +def ruby_bundle_impl(ctx, ruby_interpreter): ctx.symlink(ctx.attr.gemfile, ctx.attr.gemfile.name) if ctx.attr.gemfile_lock: ctx.symlink(ctx.attr.gemfile_lock, ctx.attr.gemfile_lock.name) @@ -181,23 +192,29 @@ def _ruby_bundle_impl(ctx): # Setup this provider that we pass around between functions for convenience runtime_ctx = RubyRuntimeInfo( ctx = ctx, - interpreter = ctx.path(ctx.attr.ruby_interpreter), + interpreter = ruby_interpreter, environment = {"RUBYOPT": "--enable-gems"}, ) + result = run_bundler( + runtime_ctx, + ["clean"], + None, + ) + # 1. Install the right version of the Bundler Gem result = install_bundler(runtime_ctx, bundler_version) - # 2. Set Bundler config in the .bundle/config file + # 2. Generate a Gemfile.lock file if one isn't provided + if not runtime_ctx.ctx.attr.gemfile_lock: + result = set_bundler_config(runtime_ctx, result, has_lock = False) + result = bundle_install(runtime_ctx, result) + + # 3. Set Bundler config in the .bundle/config file result = set_bundler_config(runtime_ctx, result) - # 3. Run bundle install + # 4. Run bundle install result = bundle_install(runtime_ctx, result) - # 4. Generate the BUILD file for the bundle + # 5. Generate the BUILD file for the bundle generate_bundle_build_file(runtime_ctx, result) - -ruby_bundle_install = repository_rule( - implementation = _ruby_bundle_impl, - attrs = BUNDLE_ATTRS, -) diff --git a/ruby/private/constants.bzl b/ruby/private/constants.bzl index a76f8f3f..4bafff0a 100644 --- a/ruby/private/constants.bzl +++ b/ruby/private/constants.bzl @@ -1,7 +1,7 @@ # Ruby Constants load(":providers.bzl", "RubyLibraryInfo") -RULES_RUBY_WORKSPACE_NAME = "@bazelruby_rules_ruby" +RULES_RUBY_WORKSPACE_NAME = "@rules_ruby" TOOLCHAIN_TYPE_NAME = "%s//ruby:toolchain_type" % RULES_RUBY_WORKSPACE_NAME DEFAULT_BUNDLER_VERSION = "2.1.4" @@ -38,6 +38,10 @@ RUBY_ATTRS = { allow_single_file = True, default = "binary_wrapper.tpl", ), + "_runner_template": attr.label( + allow_single_file = True, + default = "binary_runner.tpl", + ), "_misc_deps": attr.label_list( allow_files = True, default = ["@bazel_tools//tools/bash/runfiles"], @@ -66,12 +70,6 @@ RSPEC_ATTRS.update(RUBY_ATTRS) RSPEC_ATTRS.update(_RSPEC_ATTRS) BUNDLE_ATTRS = { - "ruby_sdk": attr.string( - default = "@org_ruby_lang_ruby_toolchain", - ), - "ruby_interpreter": attr.label( - default = "@org_ruby_lang_ruby_toolchain//:ruby", - ), "gemfile": attr.label( allow_single_file = True, mandatory = True, @@ -154,3 +152,48 @@ GEMSPEC_ATTRS = { default = "%s//ruby/private/gemspec:readme_template.tpl" % RULES_RUBY_WORKSPACE_NAME, ), } + +# The full list of supported pinned version numbers. +SUPPORTED_VERSIONS = [ + "system", + "ruby-2.5.8", + "ruby-2.5.9", + "ruby-2.6.3", + "ruby-2.6.4", + "ruby-2.6.5", + "ruby-2.6.6", + "ruby-2.6.7", + "ruby-2.6.8", + "ruby-2.6.9", + "ruby-2.7.1", + "ruby-2.7.2", + "ruby-2.7.3", + "ruby-2.7.4", + "ruby-2.7.5", + "ruby-3.0.0", + "ruby-3.0.1", + "ruby-3.0.2", + "ruby-3.0.3", + "ruby-3.1.0", + "ruby-3.1.1", + "jruby-9.2.21.0", # Corresponded to 2.5.8 + "jruby-9.3.10.0", # Corresponds to 2.6.8 + "jruby-9.4.3.0", # Corresponds to 3.1.4 +] + +def get_supported_version(version): + """Transforms a user-friendly version identifier to a full version number.""" + + if version[0] >= "0" and version[1] <= "9": + version = "ruby-" + version + + supported_version = None + for v in sorted(SUPPORTED_VERSIONS, reverse = True): + if v.startswith(version): + supported_version = v + break + + if not supported_version: + fail("ruby_runtime: unsupported ruby version '%s' not in '%s'" % (version, SUPPORTED_VERSIONS)) + + return supported_version diff --git a/ruby/private/dependencies.bzl b/ruby/private/dependencies.bzl index 0a51d7a9..589a821e 100644 --- a/ruby/private/dependencies.bzl +++ b/ruby/private/dependencies.bzl @@ -3,6 +3,7 @@ Dependencies """ load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") +load(":constants.bzl", "RULES_RUBY_WORKSPACE_NAME") def rules_ruby_dependencies(): if "bazel_skylib" not in native.existing_rules(): @@ -24,3 +25,17 @@ def rules_ruby_dependencies(): sha256 = "85e26971904cbb387688bd2a9e87c105f7cd7d986dc1b96bb1391924479c5ef6", strip_prefix = "rules_pkg-3e0cd514ad1cdd2d23ab3d427d34436f75060018/pkg", ) + + # Register placeholders for the system ruby. + native.bind( + name = "rules_ruby_system_jruby_implementation", + actual = "%s//:missing_jruby_implementation" % RULES_RUBY_WORKSPACE_NAME, + ) + native.bind( + name = "rules_ruby_system_ruby_implementation", + actual = "%s//:missing_ruby_implementation" % RULES_RUBY_WORKSPACE_NAME, + ) + native.bind( + name = "rules_ruby_system_no_implementation", + actual = "%s//:missing_no_implementation" % RULES_RUBY_WORKSPACE_NAME, + ) diff --git a/ruby/private/providers.bzl b/ruby/private/providers.bzl index 131f3355..624a5302 100644 --- a/ruby/private/providers.bzl +++ b/ruby/private/providers.bzl @@ -19,6 +19,18 @@ RubyRuntimeInfo = provider( ], ) +RubyRuntimeToolchainInfo = provider( + doc = "Information about a Ruby interpreter, related commands and libraries", + fields = { + "interpreter": "A label which points the Ruby interpreter", + "bundler": "A label which points bundler command", + "runtime": "A list of labels which points runtime libraries", + "jars": "A list of labels which points to ruby jars", + "headers": "A list of labels which points to the ruby headers", + "rubyopt": "A list of strings which should be passed to the interpreter as command line options", + }, +) + RubyGemInfo = provider( doc = "Carries info required to package a ruby gem", fields = [ diff --git a/ruby/private/rubocop/def.bzl b/ruby/private/rubocop/def.bzl index 03199063..28cb2404 100644 --- a/ruby/private/rubocop/def.bzl +++ b/ruby/private/rubocop/def.bzl @@ -1,4 +1,4 @@ -load("@bazelruby_rules_ruby//ruby/private:binary.bzl", "ruby_binary") +load("@rules_ruby//ruby/private:binary.bzl", "ruby_binary") # This wraps an rb_binary in a script that is executed from the workspace folder def rubocop(name, bin, deps): @@ -9,7 +9,7 @@ def rubocop(name, bin, deps): deps = deps, ) - runner = "@bazelruby_rules_ruby//ruby/private/rubocop:runner.sh.tpl" + runner = "@rules_ruby//ruby/private/rubocop:runner.sh.tpl" native.genrule( name = name, tools = [bin_name], diff --git a/ruby/private/runtime_alias.bzl b/ruby/private/runtime_alias.bzl new file mode 100644 index 00000000..8da00859 --- /dev/null +++ b/ruby/private/runtime_alias.bzl @@ -0,0 +1,98 @@ +load("@bazel_skylib//rules:common_settings.bzl", "BuildSettingInfo") +load("@rules_java//java:defs.bzl", "java_binary") +load(":constants.bzl", "TOOLCHAIN_TYPE_NAME") +load(":providers.bzl", "RubyRuntimeToolchainInfo") + +# These rules expose the runtime targets of whichever toolchain has been resolved. + +def _ruby_runtime_alias_impl(ctx): + ruby = ctx.toolchains[TOOLCHAIN_TYPE_NAME].ruby_runtime + return [ + DefaultInfo( + runfiles = ctx.runfiles(transitive_files = depset(ruby.runtime)), + files = depset(ruby.runtime), + ), + ruby, + ] + +ruby_runtime_alias = rule( + implementation = _ruby_runtime_alias_impl, + toolchains = [TOOLCHAIN_TYPE_NAME], +) + +def _ruby_jars_alias_impl(ctx): + runtime = ctx.attr.runtime[RubyRuntimeToolchainInfo] + target = runtime.jars + infos = [ + DefaultInfo( + files = target.files, + runfiles = ctx.runfiles(transitive_files = target.files), + ), + ] + for jar in infos[0].files.to_list(): + infos.append(JavaInfo(jar, jar)) + + return infos + +ruby_jars_alias = rule( + implementation = _ruby_jars_alias_impl, + attrs = { + "runtime": attr.label( + doc = "The runtime alias to use.", + mandatory = True, + ), + }, +) + +def _ruby_headers_alias_impl(ctx): + runtime = ctx.attr.runtime[RubyRuntimeToolchainInfo] + target = runtime.headers + return [ + ctx.attr.runtime[DefaultInfo], + target[CcInfo], + target[InstrumentedFilesInfo], + target[OutputGroupInfo], + ] + +ruby_headers_alias = rule( + implementation = _ruby_headers_alias_impl, + attrs = { + "runtime": attr.label( + doc = "The runtime alias to use.", + mandatory = True, + ), + }, +) + +def _ruby_interpreter_alias_impl(ctx): + runtime = ctx.attr.runtime[RubyRuntimeToolchainInfo] + target = runtime.interpreter + output = ctx.actions.declare_file("ruby_interpreter") + + ctx.actions.symlink( + output = output, + target_file = target[DefaultInfo].files_to_run.executable, + is_executable = True, + ) + runfiles = ctx.attr.runtime[DefaultInfo].default_runfiles.merge( + ctx.attr.runtime[DefaultInfo].data_runfiles, + ) + + return [ + DefaultInfo( + files = target.files, + runfiles = runfiles, + executable = output, + ), + ] + +ruby_interpreter_alias = rule( + implementation = _ruby_interpreter_alias_impl, + executable = True, + attrs = { + "runtime": attr.label( + doc = "The runtime alias to use.", + mandatory = True, + ), + }, +) diff --git a/ruby/private/sdk.bzl b/ruby/private/sdk.bzl index 71235754..da84961c 100644 --- a/ruby/private/sdk.bzl +++ b/ruby/private/sdk.bzl @@ -1,43 +1,61 @@ -load( - "@bazelruby_rules_ruby//ruby/private/toolchains:ruby_runtime.bzl", - _ruby_runtime = "ruby_runtime", -) - -def rules_ruby_select_sdk(version = "host"): - """Registers ruby toolchains in the WORKSPACE file.""" - - supported_versions = [ - "host", - "2.5.8", - "2.5.9", - "2.6.3", - "2.6.4", - "2.6.5", - "2.6.6", - "2.6.7", - "2.6.8", - "2.6.9", - "2.7.1", - "2.7.2", - "2.7.3", - "2.7.4", - "2.7.5", - "3.0.0", - "3.0.1", - "3.0.2", - "3.0.3", - "3.1.0", - "3.1.1", - ] - - if version in supported_versions: - _ruby_runtime( - name = "org_ruby_lang_ruby_toolchain", - version = version, - ) - else: - fail("rules_ruby_select_sdk: unsupported ruby version '%s' not in '%s'" % (version, supported_versions)) +load("@rules_ruby//ruby/private/toolchains:ruby_runtime.bzl", "ruby_runtime") +load(":constants.bzl", "RULES_RUBY_WORKSPACE_NAME", "get_supported_version") + +def register_ruby_runtime(name, version = None): + """Initializes a ruby toolchain at a specific version. + + A special version "system" or "system_ruby" will use whatever version of + ruby is installed on the host system. Besides that, this rules supports all + of versions in the SUPPORTED_VERSIONS list. The most recent matching + version will beselected. + + If the current system ruby doesn't match a given version, it will be + downloaded and built for use by the toolchain. Toolchain selection occurs + based on the //ruby/runtime:version flag setting. + + For example, `register_toolchains("ruby", "ruby-2.5")` will download and + build the latest supported version of Ruby 2.5. + By default, the system ruby will be used for all Bazel build and + tests. However, passing a flag such as: + --@rules_ruby//ruby/runtime:version="ruby-2.5" + will select the Ruby 2.5 installation. + + Optionally, a single string can be passed to this macro and it will use it + for both the name and version. + + Args: + name: the name of the generated Bazel repository + version: a version identifier (e.g. system, ruby-2.5, jruby-9.4) + """ + if not version: + version = name + if version == "system_ruby": + # Special handling to give the system ruby repo a friendly name. + version = "system" - native.register_toolchains( - "@org_ruby_lang_ruby_toolchain//:toolchain", + supported_version = get_supported_version(version) + if supported_version.startswith("ruby-"): + supported_version = supported_version[5:] + + ruby_runtime( + name = name, + version = supported_version, ) + + if supported_version == "system": + native.bind( + name = "rules_ruby_system_jruby_implementation", + actual = "@%s//:jruby_implementation" % name, + ) + native.bind( + name = "rules_ruby_system_ruby_implementation", + actual = "@%s//:ruby_implementation" % name, + ) + native.bind( + name = "rules_ruby_system_no_implementation", + actual = "@%s//:no_implementation" % name, + ) + native.bind( + name = "rules_ruby_system_interpreter", + actual = "@%s//:ruby" % name, + ) diff --git a/ruby/private/toolchain.bzl b/ruby/private/toolchain.bzl index cbaebd67..8af44df2 100644 --- a/ruby/private/toolchain.bzl +++ b/ruby/private/toolchain.bzl @@ -1,21 +1,14 @@ load(":constants.bzl", "RULES_RUBY_WORKSPACE_NAME") - -RubyRuntimeInfo = provider( - doc = "Information about a Ruby interpreter, related commands and libraries", - fields = { - "interpreter": "A label which points the Ruby interpreter", - "bundler": "A label which points bundler command", - "runtime": "A list of labels which points runtime libraries", - "rubyopt": "A list of strings which should be passed to the interpreter as command line options", - }, -) +load(":providers.bzl", "RubyRuntimeToolchainInfo") def _ruby_toolchain_impl(ctx): return [ platform_common.ToolchainInfo( - ruby_runtime = RubyRuntimeInfo( + ruby_runtime = RubyRuntimeToolchainInfo( interpreter = ctx.attr.interpreter, runtime = ctx.files.runtime, + jars = ctx.attr.jars, + headers = ctx.attr.headers, rubyopt = ctx.attr.rubyopt, ), ), @@ -35,6 +28,16 @@ _ruby_toolchain = rule( allow_files = True, cfg = "target", ), + "jars": attr.label( + mandatory = True, + allow_files = True, + cfg = "target", + ), + "headers": attr.label( + mandatory = True, + allow_files = True, + cfg = "target", + ), "rubyopt": attr.string_list( default = [], ), @@ -45,6 +48,8 @@ def ruby_toolchain( name, interpreter, runtime, + jars, + headers, rubyopt = [], rules_ruby_workspace = RULES_RUBY_WORKSPACE_NAME, **kwargs): @@ -53,6 +58,8 @@ def ruby_toolchain( name = impl_name, interpreter = interpreter, runtime = runtime, + jars = jars, + headers = headers, rubyopt = rubyopt, ) @@ -62,3 +69,29 @@ def ruby_toolchain( toolchain = ":%s" % impl_name, **kwargs ) + +def _mock_ruby_toolchain_impl(ctx): + return [ + platform_common.ToolchainInfo(), + ] + +_mock_ruby_toolchain = rule( + implementation = _mock_ruby_toolchain_impl, +) + +def mock_ruby_toolchain( + name, + rules_ruby_workspace = RULES_RUBY_WORKSPACE_NAME, + **kwargs): + impl_name = name + "_sdk" + _mock_ruby_toolchain( + name = impl_name, + ) + native.toolchain( + name = name, + toolchain_type = "%s//ruby:toolchain_type" % rules_ruby_workspace, + toolchain = ":%s" % impl_name, + exec_compatible_with = ["@platforms//:incompatible"], + target_compatible_with = ["@platforms//:incompatible"], + **kwargs + ) diff --git a/ruby/private/toolchains/BUILD b/ruby/private/toolchains/BUILD deleted file mode 100644 index 67efa96b..00000000 --- a/ruby/private/toolchains/BUILD +++ /dev/null @@ -1 +0,0 @@ -package(default_visibility = ["//ruby/private:__pkg__"]) diff --git a/ruby/private/toolchains/BUILD.bazel b/ruby/private/toolchains/BUILD.bazel new file mode 100644 index 00000000..282fec80 --- /dev/null +++ b/ruby/private/toolchains/BUILD.bazel @@ -0,0 +1,38 @@ +load("@bazel_skylib//lib:selects.bzl", "selects") +load("@bazel_skylib//rules:common_settings.bzl", "string_flag") + +package(default_visibility = ["//ruby/private:__pkg__"]) + +# Placeholders for cases when no system ruby is requested +string_flag( + name = "internal_missing_ruby", + build_setting_default = "none", + values = [ + "none", + "ruby", + "jruby", + ], +) + +config_setting( + name = "missing_jruby_implementation", + flag_values = { + ":internal_ruby_implementation": "jruby", + }, +) + +config_setting( + name = "missing_ruby_implementation", + flag_values = { + ":internal_ruby_implementation": "ruby", + }, +) + +config_setting( + name = "missing_no_implementation", + flag_values = { + ":internal_ruby_implementation": "none", + }, +) + +# vim: set ft=bzl : diff --git a/ruby/private/toolchains/BUILD.runtime.tpl b/ruby/private/toolchains/BUILD.runtime.tpl index fbb3e64b..d4bb281b 100644 --- a/ruby/private/toolchains/BUILD.runtime.tpl +++ b/ruby/private/toolchains/BUILD.runtime.tpl @@ -1,49 +1,44 @@ -load( - "{rules_ruby_workspace}//ruby:defs.bzl", - "ruby_library", - "ruby_toolchain", -) +load("@bazel_skylib//lib:selects.bzl", "selects") +load("@bazel_skylib//rules:common_settings.bzl", "string_flag") package(default_visibility = ["//visibility:public"]) -ruby_toolchain( - name = "toolchain", - interpreter = "//:ruby_bin", - rules_ruby_workspace = "{rules_ruby_workspace}", - runtime = "//:runtime", - # TODO(yugui) Extract platform info from RbConfig - # exec_compatible_with = [], - # target_compatible_with = [], -) +# Toolchain targets. These will be mocked out with stubs if no ruby version +# can be found. +{toolchain} -sh_binary( - name = "ruby_bin", - srcs = ["ruby"], - data = [":runtime"], +# Provide config settings to signal the ruby platform to downstream code. +# This should never be overridden, and is determined automatically during the +# creation of the toolchain. +string_flag( + name = "internal_ruby_implementation", + build_setting_default = "{implementation}", + values = [ + "none", + "ruby", + "jruby", + ], ) -cc_import( - name = "libruby", - hdrs = glob({hdrs}), - shared_library = {shared_library}, - static_library = {static_library}, +config_setting( + name = "jruby_implementation", + flag_values = { + ":internal_ruby_implementation": "jruby", + }, ) -cc_library( - name = "headers", - hdrs = glob({hdrs}), - includes = {includes}, +config_setting( + name = "ruby_implementation", + flag_values = { + ":internal_ruby_implementation": "ruby", + }, ) -filegroup( - name = "runtime", - srcs = glob( - include = ["**/*"], - exclude = [ - "BUILD.bazel", - "WORKSPACE", - ], - ), +config_setting( + name = "no_implementation", + flag_values = { + ":internal_ruby_implementation": "none", + }, ) # vim: set ft=bzl : diff --git a/ruby/private/toolchains/ruby_runtime.bzl b/ruby/private/toolchains/ruby_runtime.bzl index 5e533778..651366cd 100644 --- a/ruby/private/toolchains/ruby_runtime.bzl +++ b/ruby/private/toolchains/ruby_runtime.bzl @@ -1,19 +1,152 @@ load("//ruby/private:constants.bzl", "RULES_RUBY_WORKSPACE_NAME") load("//ruby/private/toolchains:repository_context.bzl", "ruby_repository_context") +_mock_toolchain = """ +load( + "{rules_ruby_workspace}//ruby:defs.bzl", + "ruby_mock_toolchain", +) + +ruby_mock_toolchain( + name = "toolchain", + rules_ruby_workspace = "{rules_ruby_workspace}", +) + +sh_binary( + name = "ruby_bin", + srcs = ["ruby"], + data = [":runtime"], +) + +cc_import( + name = "libruby", + hdrs = [], +) + +cc_library( + name = "headers", + hdrs = [], + includes = [], +) + +java_binary( + name = "dummy_jar", + srcs = ["Dummy.java"], +) + +filegroup( + name = "jars", + srcs = [":dummy_jar"], +) + +filegroup( + name = "runtime", + srcs = [], +) +""" + +_toolchain = """ +load( + "{rules_ruby_workspace}//ruby:defs.bzl", + "ruby_toolchain", +) + +ruby_toolchain( + name = "toolchain", + interpreter = "//:ruby_bin", + rules_ruby_workspace = "{rules_ruby_workspace}", + runtime = "//:runtime", + jars = "//:jars", + headers = "//:headers", + target_settings = [ + "{rules_ruby_workspace}//ruby/runtime:{setting}" + ], + # TODO(yugui) Extract platform info from RbConfig + # exec_compatible_with = [], + # target_compatible_with = [], +) + +sh_binary( + name = "ruby_bin", + srcs = ["ruby"], + data = [":runtime"], +) + +cc_import( + name = "libruby", + hdrs = glob({hdrs}, allow_empty = True), + shared_library = {shared_library}, + static_library = {static_library}, +) + +cc_library( + name = "headers", + hdrs = glob({hdrs}, allow_empty = True), + includes = {includes}, +) + +java_library( + name = "dummy_jar", + srcs = ["Dummy.java"], +) + +filegroup( + name = "jars", + srcs = {jars}, +) + +filegroup( + name = "runtime", + srcs = glob( + include = ["**/*"], + exclude = [ + "BUILD.bazel", + "WORKSPACE", + ], + ), +) +""" + +# Define a dummy java file for creating a no-op jar when JRuby isn't selected. +_dummy_jar = """ +public class Dummy { + public static void main(String[] args) {} +} +""" + +_bundle_bzl = """ +load("{rules_ruby_workspace}//ruby/private/bundle:def.bzl", "ruby_bundle_impl") +load("{rules_ruby_workspace}//ruby/private:constants.bzl", "BUNDLE_ATTRS") + +def _ruby_bundle_impl(ctx): + ruby_bundle_impl(ctx, "{interpreter}") + +ruby_bundle = repository_rule( + implementation = _ruby_bundle_impl, + attrs = BUNDLE_ATTRS, +) +""" + +_mock_bundle_bzl = """ +def ruby_bundle(**kwargs): + print("WARNING: no system ruby found for bundle") +""" + def _install_ruby_version(ctx, version): ctx.download_and_extract( - url = "https://github.com/rbenv/ruby-build/archive/refs/tags/v20220218.tar.gz", - sha256 = "35c82b13b7bc3713eee5615b0145c79fbbac32873f55f2ab796620d76970d8e3", - stripPrefix = "ruby-build-20220218", + url = "https://github.com/rbenv/ruby-build/archive/refs/tags/v20230710.tar.gz", + sha256 = "8c9cf458d461a9b6b63d44e4b5b246304168f665fd47adea1733ab6a7cd0f077", + stripPrefix = "ruby-build-20230710", ) install_path = "./build" - ctx.execute( + result = ctx.execute( ["./bin/ruby-build", "--verbose", version, install_path], quiet = False, timeout = 1600, # massive timeout because this does a lot and is a beast ) + if result.return_code: + fail("Ruby build failed: %s %s" % (result.stdout, result.stderr)) def _is_subpath(path, ancestors): """Determines if path is a subdirectory of one of the ancestors""" @@ -99,14 +232,27 @@ def _install_ruby(ctx, ruby): shared_library = _relativate(shared_library), ) -def host_ruby_is_correct_version(ctx, version): +def get_ruby_info(ctx, interpreter_path): + platform = ctx.execute([interpreter_path, "-e", "print RUBY_PLATFORM"]).stdout + if platform == "java": + ruby_impl = "jruby" + ruby_version = ctx.execute([interpreter_path, "-e", "print JRUBY_VERSION"]).stdout + else: + ruby_impl = "ruby" + ruby_version = ctx.execute([interpreter_path, "-e", "print RUBY_VERSION"]).stdout + + return ruby_impl, ruby_version + +def system_ruby_is_correct_version(ctx, version): interpreter_path = ctx.which("ruby") if not interpreter_path: print("Can't find ruby interpreter in the PATH") return False - ruby_version = ctx.execute(["ruby", "-e", "print RUBY_VERSION"]).stdout + ruby_impl, ruby_version = get_ruby_info(ctx, interpreter_path) + if ruby_impl == "jruby": + ruby_version = "jruby-" + ruby_version have_ruby_version = (version == ruby_version) @@ -118,39 +264,60 @@ def host_ruby_is_correct_version(ctx, version): def _ruby_runtime_impl(ctx): # If the current version of ruby is correct use that version = ctx.attr.version - if version == "host" or host_ruby_is_correct_version(ctx, version): + if version == "system" or system_ruby_is_correct_version(ctx, version): interpreter_path = ctx.which("ruby") else: _install_ruby_version(ctx, version) interpreter_path = ctx.path("./build/bin/ruby") + if not interpreter_path or not interpreter_path.exists: + fail("Installation of ruby version %s failed") - if not interpreter_path: - fail( - "Command 'ruby' not found. Set $PATH or specify interpreter_path", - "interpreter_path", - ) - - ruby = ruby_repository_context(ctx, interpreter_path) + ctx.file("Dummy.java", _dummy_jar) - installed = _install_ruby(ctx, ruby) + if interpreter_path and interpreter_path.exists: + ruby = ruby_repository_context(ctx, interpreter_path) + installed = _install_ruby(ctx, ruby) + ruby_impl, ruby_version = get_ruby_info(ctx, interpreter_path) + hdrs = ["%s/**/*.h" % path for path in installed.includedirs] + toolchain = _toolchain.format( + includes = repr(installed.includedirs), + hdrs = repr(["%s/**/*.h" % path for path in installed.includedirs]), + jars = "glob([\"**/lib/jruby.jar\"])" if ruby_impl == "jruby" else [":dummy_jar"], + static_library = repr(installed.static_library), + shared_library = repr(installed.shared_library), + rules_ruby_workspace = RULES_RUBY_WORKSPACE_NAME, + version = ruby_version, + setting = "config_system" if version == "system" else "config_%s-%s" % (ruby_impl, ruby_version), + ) + bundle_bzl = _bundle_bzl.format( + interpreter = ruby.interpreter_realpath, + rules_ruby_workspace = RULES_RUBY_WORKSPACE_NAME, + ) + else: + print("WARNING: no system ruby available, builds against system ruby will fail") + support = "none" + ruby_impl = "none" + toolchain = _mock_toolchain.format( + rules_ruby_workspace = RULES_RUBY_WORKSPACE_NAME, + ) + ctx.file("ruby", content = "", executable = True) + bundle_bzl = _mock_bundle_bzl ctx.template( "BUILD.bazel", ctx.attr._buildfile_template, substitutions = { - "{includes}": repr(installed.includedirs), - "{hdrs}": repr(["%s/**/*.h" % path for path in installed.includedirs]), - "{static_library}": repr(installed.static_library), - "{shared_library}": repr(installed.shared_library), - "{rules_ruby_workspace}": RULES_RUBY_WORKSPACE_NAME, + "{toolchain}": toolchain, + "{implementation}": ruby_impl, }, executable = False, ) + ctx.file("bundle.bzl", bundle_bzl) ruby_runtime = repository_rule( implementation = _ruby_runtime_impl, attrs = { - "version": attr.string(default = "host"), + "version": attr.string(default = "system"), "_buildfile_template": attr.label( default = "%s//ruby/private/toolchains:BUILD.runtime.tpl" % ( RULES_RUBY_WORKSPACE_NAME @@ -164,4 +331,9 @@ ruby_runtime = repository_rule( allow_single_file = True, ), }, + # Force a re-fetch when the Ruby version is changed through RVM. + # This will also force a re-download when PATH changes, which is + # unnecessary. To fix this, we may want to make system_ruby() + # a different repository rule from ruby_runtime(). + environ = ["PATH"], ) diff --git a/ruby/runtime/BUILD.bazel b/ruby/runtime/BUILD.bazel new file mode 100644 index 00000000..288e3d14 --- /dev/null +++ b/ruby/runtime/BUILD.bazel @@ -0,0 +1,139 @@ +load("@bazel_skylib//lib:selects.bzl", "selects") +load("@bazel_skylib//rules:common_settings.bzl", "string_flag") +load("@rules_ruby//ruby/private:constants.bzl", "get_supported_version") +load( + ":version_support.bzl", + "ALL_JRUBY_MAJOR_MINOR_VERSIONS", + "ALL_RUBY_MAJOR_MINOR_VERSIONS", + "SUPPORTED_MAJOR_MINOR_VERSIONS", +) +load( + "@rules_ruby//ruby/private:runtime_alias.bzl", + _ruby_headers_alias = "ruby_headers_alias", + _ruby_interpreter_alias = "ruby_interpreter_alias", + _ruby_jars_alias = "ruby_jars_alias", + _ruby_runtime_alias = "ruby_runtime_alias", +) + +package(default_visibility = ["//visibility:public"]) + +toolchain_type(name = "toolchain_type") + +# Alias targets corresponding to whichever toolchain was resolved based on +# the selected version. + +_ruby_runtime_alias( + name = "runtime", +) + +_ruby_jars_alias( + name = "jars", + runtime = ":runtime", +) + +java_binary( + name = "jruby_binary", + main_class = "org.jruby.Main", + runtime_deps = [":jars"], +) + +_ruby_headers_alias( + name = "headers", + runtime = ":runtime", +) + +_ruby_interpreter_alias( + name = "interpreter", + runtime = ":runtime", +) + +# Supported ruby versions, which can be selected by flags. +# For example: --@rules_ruby//ruby/runtime:version=jruby-9.3 +string_flag( + name = "version", + build_setting_default = "auto", + values = [ + "auto", + "system", + ] + SUPPORTED_MAJOR_MINOR_VERSIONS, +) + +config_setting( + name = "config_auto", + flag_values = {"version": "auto"}, +) + +config_setting( + name = "internal_config_system", + flag_values = {"version": "system"}, +) + +[ + config_setting( + name = "internal_config_" + get_supported_version(version), + flag_values = {"version": version}, + ) + for version in SUPPORTED_MAJOR_MINOR_VERSIONS +] + +selects.config_setting_group( + name = "config_system", + match_any = [ + ":config_auto", + ":internal_config_system", + ], +) + +[ + selects.config_setting_group( + name = "config_" + get_supported_version(version), + match_any = [ + ":internal_config_" + get_supported_version(version), + ], + ) + for version in SUPPORTED_MAJOR_MINOR_VERSIONS +] + +[ + alias( + name = "config_" + version, + actual = ":config_" + get_supported_version(version), + ) + for version in SUPPORTED_MAJOR_MINOR_VERSIONS +] + +selects.config_setting_group( + name = "config_system_ruby", + match_all = [ + ":config_system", + "//external:rules_ruby_system_ruby_implementation", + ], +) + +selects.config_setting_group( + name = "config_ruby", + match_any = [":config_system_ruby"] + + [":config_%s" % v for v in ALL_RUBY_MAJOR_MINOR_VERSIONS], +) + +selects.config_setting_group( + name = "config_system_jruby", + match_all = [ + ":config_system", + "//external:rules_ruby_system_jruby_implementation", + ], +) + +selects.config_setting_group( + name = "config_jruby", + match_any = [":config_system_jruby"] + + [":config_%s" % v for v in ALL_JRUBY_MAJOR_MINOR_VERSIONS], +) + +selects.config_setting_group( + name = "config_system_none", + match_all = [ + ":config_system", + "//external:rules_ruby_system_no_implementation", + ], +) diff --git a/ruby/runtime/version_support.bzl b/ruby/runtime/version_support.bzl new file mode 100644 index 00000000..40dfa63d --- /dev/null +++ b/ruby/runtime/version_support.bzl @@ -0,0 +1,26 @@ +load("@bazel_skylib//lib:new_sets.bzl", "sets") +load( + "@rules_ruby//ruby/private:constants.bzl", + "SUPPORTED_VERSIONS", +) + +def _major_minor_versions(): + """Filters supported versions to unique major/minor pairs""" + versions = sets.make() + for s in SUPPORTED_VERSIONS: + if s.find(".") < 0: + continue + split = s.find(".", s.find(".") + 1) + sets.insert(versions, s[0:split]) + return sorted(sets.to_list(versions)) + +def _filter(versions, prefix): + filtered = [] + for v in versions: + if v.startswith(prefix): + filtered.append(v) + return filtered + +SUPPORTED_MAJOR_MINOR_VERSIONS = _major_minor_versions() +ALL_RUBY_MAJOR_MINOR_VERSIONS = _filter(SUPPORTED_MAJOR_MINOR_VERSIONS, "ruby-") +ALL_JRUBY_MAJOR_MINOR_VERSIONS = _filter(SUPPORTED_MAJOR_MINOR_VERSIONS, "jruby-") diff --git a/ruby/tests/BUILD.bazel b/ruby/tests/BUILD.bazel index b3e7290e..1ac2d437 100644 --- a/ruby/tests/BUILD.bazel +++ b/ruby/tests/BUILD.bazel @@ -65,7 +65,7 @@ sh_test( ], data = [ "args_check.rb", - "@org_ruby_lang_ruby_toolchain//:ruby_bin", + "@rules_ruby//ruby/runtime:interpreter", ], ) @@ -74,7 +74,7 @@ genrule( name = "generate_genrule_run_ruby_test", outs = ["genrules_run_ruby_test.sh"], cmd = " && ".join([ - ("$(location @org_ruby_lang_ruby_toolchain//:ruby_bin) " + + ("$(location @rules_ruby//ruby/runtime:interpreter) " + "$(location args_check.rb) foo bar baz"), "echo '#!/bin/sh -e' > $@", "echo true >> $@", @@ -83,8 +83,8 @@ genrule( output_to_bindir = 1, tools = [ "args_check.rb", - "@org_ruby_lang_ruby_toolchain//:ruby_bin", - "@org_ruby_lang_ruby_toolchain//:runtime", + "@rules_ruby//ruby/runtime", + "@rules_ruby//ruby/runtime:interpreter", ], ) @@ -120,7 +120,7 @@ ruby_binary( main = "load_path_in_runfiles_test.rb", deps = [ "//ruby/tests/testdata:g", - "@bazelruby_rules_ruby_ruby_tests_testdata_another_workspace//baz/qux:j", + "@rules_ruby_ruby_tests_testdata_another_workspace//baz/qux:j", ], ) @@ -137,7 +137,7 @@ ruby_test( main = "load_path_in_runfiles_test.rb", deps = [ "//ruby/tests/testdata:g", - "@bazelruby_rules_ruby_ruby_tests_testdata_another_workspace//baz/qux:j", + "@rules_ruby_ruby_tests_testdata_another_workspace//baz/qux:j", ], ) @@ -188,7 +188,7 @@ cc_binary( testonly = True, srcs = ["example_ext.c"], linkshared = True, - deps = ["@org_ruby_lang_ruby_toolchain//:headers"], + deps = ["@rules_ruby//ruby/runtime:headers"], ) cc_library( @@ -197,7 +197,7 @@ cc_library( srcs = ["example_ext.c"], linkstatic = True, tags = ["manual"], - deps = ["@org_ruby_lang_ruby_toolchain//:headers"], + deps = ["@rules_ruby//ruby/runtime:headers"], alwayslink = True, ) @@ -250,13 +250,13 @@ pkg_tar( include_runfiles = True, package_dir = "/app", remap_paths = { - "ruby": "load_path_in_runfiles.runfiles/bazelruby_rules_ruby/ruby", + "ruby": "load_path_in_runfiles.runfiles/rules_ruby/ruby", ".": "load_path_in_runfiles.runfiles/", }, strip_prefix = "dummy", symlinks = { - "/app/load_path_in_runfiles.runfiles/bazelruby_rules_ruby/external": "/app/load_path_in_runfiles.runfiles", - "/app/load_path_in_runfiles": "/app/load_path_in_runfiles.runfiles/bazelruby_rules_ruby/ruby/tests/load_path_in_runfiles", + "/app/load_path_in_runfiles.runfiles/rules_ruby/external": "/app/load_path_in_runfiles.runfiles", + "/app/load_path_in_runfiles": "/app/load_path_in_runfiles.runfiles/rules_ruby/ruby/tests/load_path_in_runfiles", }, ) diff --git a/ruby/tests/load_path_in_runfiles_test.rb b/ruby/tests/load_path_in_runfiles_test.rb index 95218273..1af9a4ea 100644 --- a/ruby/tests/load_path_in_runfiles_test.rb +++ b/ruby/tests/load_path_in_runfiles_test.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true require 'ruby/tests/testdata/foo/g' -require 'external/bazelruby_rules_ruby_ruby_tests_testdata_another_workspace/baz/qux/j' +require 'external/rules_ruby_ruby_tests_testdata_another_workspace/baz/qux/j' [g, j] diff --git a/ruby/tests/runtime_run_ruby_test.sh b/ruby/tests/runtime_run_ruby_test.sh index 6a3e270d..7de0ac8c 100755 --- a/ruby/tests/runtime_run_ruby_test.sh +++ b/ruby/tests/runtime_run_ruby_test.sh @@ -1,2 +1,2 @@ #!/bin/sh -e -external/org_ruby_lang_ruby_toolchain/ruby_bin $* +ruby/runtime/ruby_interpreter $* diff --git a/ruby/tests/testdata/another_workspace/WORKSPACE b/ruby/tests/testdata/another_workspace/WORKSPACE index 86ed1c1f..0f914eb0 100644 --- a/ruby/tests/testdata/another_workspace/WORKSPACE +++ b/ruby/tests/testdata/another_workspace/WORKSPACE @@ -1,5 +1,7 @@ -workspace(name = "bazelruby_rules_ruby_ruby_tests_testdata_another_workspace") +workspace(name = "rules_ruby_ruby_tests_testdata_another_workspace") -load("@bazelruby_rules_ruby//ruby:defs.bzl", "rules_ruby_select_sdk") +load("@rules_ruby//ruby:defs.bzl", "ruby_runtime") -rules_ruby_select_sdk() +ruby_runtime("system_ruby") + +register_toolchains("@system_ruby//:toolchain") diff --git a/ruby/tests/testdata/another_workspace/baz/qux/BUILD.bazel b/ruby/tests/testdata/another_workspace/baz/qux/BUILD.bazel index 89a2dfed..96d5c614 100644 --- a/ruby/tests/testdata/another_workspace/baz/qux/BUILD.bazel +++ b/ruby/tests/testdata/another_workspace/baz/qux/BUILD.bazel @@ -1,4 +1,4 @@ -load("@bazelruby_rules_ruby//ruby:defs.bzl", "ruby_library") +load("@rules_ruby//ruby:defs.bzl", "ruby_library") package(default_visibility = ["//visibility:public"]) diff --git a/ruby/tests/testdata/bundle_includes_workspace/BUILD.bazel b/ruby/tests/testdata/bundle_includes_workspace/BUILD.bazel index 01b33fa7..5663a68a 100644 --- a/ruby/tests/testdata/bundle_includes_workspace/BUILD.bazel +++ b/ruby/tests/testdata/bundle_includes_workspace/BUILD.bazel @@ -1,5 +1,5 @@ load( - "@bazelruby_rules_ruby//ruby:defs.bzl", + "@rules_ruby//ruby:defs.bzl", "ruby_binary", ) diff --git a/ruby/tests/testdata/bundle_includes_workspace/WORKSPACE b/ruby/tests/testdata/bundle_includes_workspace/WORKSPACE index 00a3bb41..25c14f53 100644 --- a/ruby/tests/testdata/bundle_includes_workspace/WORKSPACE +++ b/ruby/tests/testdata/bundle_includes_workspace/WORKSPACE @@ -1,21 +1,21 @@ -workspace(name = "bazelruby_rules_ruby_ruby_tests_testdata_bundle_includes_workspace") +workspace(name = "rules_ruby_ruby_tests_testdata_bundle_includes_workspace") local_repository( - name = "bazelruby_rules_ruby", + name = "rules_ruby", path = "../../../..", ) -load( - "@bazelruby_rules_ruby//ruby:deps.bzl", - "rules_ruby_dependencies", - "rules_ruby_select_sdk", -) +load("@rules_ruby//ruby:deps.bzl", "rules_ruby_dependencies") rules_ruby_dependencies() -rules_ruby_select_sdk(version = "3.0.2") +load("@rules_ruby//ruby:defs.bzl", "ruby_runtime") + +ruby_runtime("ruby-3.0") + +register_toolchains("@ruby-3.0//:toolchain") -load("@bazelruby_rules_ruby//ruby:defs.bzl", "ruby_bundle") +load("@ruby-3.0//:bundle.bzl", "ruby_bundle") ruby_bundle( name = "gems",