diff options
author | Hiroshi SHIBATA <hsbt@ruby-lang.org> | 2022-12-22 08:20:23 +0900 |
---|---|---|
committer | Hiroshi SHIBATA <hsbt@ruby-lang.org> | 2022-12-24 16:57:07 +0900 |
commit | f6620037ba1477d2c337d7b511f094d6d0fbb69c (patch) | |
tree | 4d8d38eaf97e6ca88162dd574e7871e1739f22ae /lib/bundler | |
parent | d5635dfe36588b04d3dd6065ab4e422f51629b11 (diff) | |
download | ruby-f6620037ba1477d2c337d7b511f094d6d0fbb69c.tar.gz |
Merge RubyGems-3.4.0 and Bundler-2.4.0
Diffstat (limited to 'lib/bundler')
26 files changed, 236 insertions, 102 deletions
diff --git a/lib/bundler/cli.rb b/lib/bundler/cli.rb index a9331a0131..6745740f11 100644 --- a/lib/bundler/cli.rb +++ b/lib/bundler/cli.rb @@ -10,7 +10,7 @@ module Bundler AUTO_INSTALL_CMDS = %w[show binstubs outdated exec open console licenses clean].freeze PARSEABLE_COMMANDS = %w[check config help exec platform show version].freeze - EXTENSIONS = ["c"].freeze + EXTENSIONS = ["c", "rust"].freeze COMMAND_ALIASES = { "check" => "c", @@ -762,7 +762,7 @@ module Bundler # when deprecated version of `--ext` is called # print out deprecation warning and pretend `--ext=c` was provided if deprecated_ext_value?(arguments) - SharedHelpers.major_deprecation 2, "Option `--ext` without explicit value is deprecated. Please pass value like `--ext=c` for C extension. Pretending `--ext=c` was used for now." + SharedHelpers.major_deprecation 2, "Extensions can now be generated using C or Rust, so `--ext` with no arguments has been deprecated. Please select a language, e.g. `--ext=rust` to generate a Rust extension. This gem will now be generated as if `--ext=c` was used." arguments[arguments.index("--ext")] = "--ext=c" end end diff --git a/lib/bundler/cli/gem.rb b/lib/bundler/cli/gem.rb index 40c464cc2c..7f1200f4a0 100644 --- a/lib/bundler/cli/gem.rb +++ b/lib/bundler/cli/gem.rb @@ -31,6 +31,7 @@ module Bundler @extension = options[:ext] validate_ext_name if @extension + validate_rust_builder_rubygems_version if @extension == "rust" travis_removal_info end @@ -73,6 +74,7 @@ module Bundler :git => use_git, :github_username => github_username.empty? ? "[USERNAME]" : github_username, :required_ruby_version => required_ruby_version, + :rust_builder_required_rubygems_version => rust_builder_required_rubygems_version, :minitest_constant_name => minitest_constant_name, } ensure_safe_gem_name(name, constant_array) @@ -189,14 +191,23 @@ module Bundler templates.merge!("exe/newgem.tt" => "exe/#{name}") if config[:exe] - if extension + if extension == "c" templates.merge!( - "ext/newgem/extconf.rb.tt" => "ext/#{name}/extconf.rb", + "ext/newgem/extconf-c.rb.tt" => "ext/#{name}/extconf.rb", "ext/newgem/newgem.h.tt" => "ext/#{name}/#{underscored_name}.h", "ext/newgem/newgem.c.tt" => "ext/#{name}/#{underscored_name}.c" ) end + if extension == "rust" + templates.merge!( + "Cargo.toml.tt" => "Cargo.toml", + "ext/newgem/Cargo.toml.tt" => "ext/#{name}/Cargo.toml", + "ext/newgem/extconf-rust.rb.tt" => "ext/#{name}/extconf.rb", + "ext/newgem/src/lib.rs.tt" => "ext/#{name}/src/lib.rs", + ) + end + if target.exist? && !target.directory? Bundler.ui.error "Couldn't create a new gem named `#{gem_name}` because there's an existing file named `#{gem_name}`." exit Bundler::BundlerError.all_errors[Bundler::GenericSystemCallError] @@ -415,6 +426,10 @@ module Bundler thor.run(%(#{editor} "#{file}")) end + def rust_builder_required_rubygems_version + "3.3.11" + end + def required_ruby_version "2.6.0" end @@ -427,7 +442,6 @@ module Bundler "1.3" end - # # TODO: remove at next minor release def travis_removal_info if options[:ci] == "travis" @@ -440,5 +454,12 @@ module Bundler exit 1 end end + + def validate_rust_builder_rubygems_version + if Gem::Version.new(rust_builder_required_rubygems_version) > Gem.rubygems_version + Bundler.ui.error "Your RubyGems version (#{Gem.rubygems_version}) is too old to build Rust extension. Please update your RubyGems using `gem update --system` or any other way and try again." + exit 1 + end + end end end diff --git a/lib/bundler/definition.rb b/lib/bundler/definition.rb index 8659c64849..348f1b6a3d 100644 --- a/lib/bundler/definition.rb +++ b/lib/bundler/definition.rb @@ -263,10 +263,10 @@ module Bundler @locked_specs elsif !unlocking? && nothing_changed? if deleted_deps.any? - Bundler.ui.debug("Some dependencies were deleted, using a subset of the resolution from the lockfile") + Bundler.ui.debug "Some dependencies were deleted, using a subset of the resolution from the lockfile" SpecSet.new(filter_specs(@locked_specs, @dependencies - deleted_deps)) else - Bundler.ui.debug("Found no changes, using resolution from the lockfile") + Bundler.ui.debug "Found no changes, using resolution from the lockfile" if @locked_gems.may_include_redundant_platform_specific_gems? SpecSet.new(filter_specs(@locked_specs, @dependencies)) else @@ -274,7 +274,7 @@ module Bundler end end else - Bundler.ui.debug("Found changes from the lockfile, re-resolving dependencies because #{change_reason}") + Bundler.ui.debug "Found changes from the lockfile, re-resolving dependencies because #{change_reason}" start_resolution end end @@ -806,12 +806,13 @@ module Bundler end new_spec = new_specs[s].first - - # If the spec is no longer in the path source, unlock it. This - # commonly happens if the version changed in the gemspec - next unless new_spec - - s.dependencies.replace(new_spec.dependencies) + if new_spec + s.dependencies.replace(new_spec.dependencies) + else + # If the spec is no longer in the path source, unlock it. This + # commonly happens if the version changed in the gemspec + @unlock[:gems] << s.name + end end if dep.nil? && requested_dependencies.find {|d| s.name == d.name } diff --git a/lib/bundler/dependency.rb b/lib/bundler/dependency.rb index 695e5c12b2..1f8b9da2eb 100644 --- a/lib/bundler/dependency.rb +++ b/lib/bundler/dependency.rb @@ -7,7 +7,7 @@ require_relative "rubygems_ext" module Bundler class Dependency < Gem::Dependency attr_reader :autorequire - attr_reader :groups, :platforms, :gemfile, :path, :git, :github, :branch, :ref, :force_ruby_platform + attr_reader :groups, :platforms, :gemfile, :path, :git, :github, :branch, :ref ALL_RUBY_VERSIONS = ((18..27).to_a + (30..31).to_a).freeze PLATFORM_MAP = { @@ -42,7 +42,7 @@ module Bundler @env = options["env"] @should_include = options.fetch("should_include", true) @gemfile = options["gemfile"] - @force_ruby_platform = options["force_ruby_platform"] + @force_ruby_platform = options["force_ruby_platform"] if options.key?("force_ruby_platform") @autorequire = Array(options["require"] || []) if options.key?("require") end @@ -50,7 +50,7 @@ module Bundler # Returns the platforms this dependency is valid for, in the same order as # passed in the `valid_platforms` parameter def gem_platforms(valid_platforms) - return [Gem::Platform::RUBY] if @force_ruby_platform + return [Gem::Platform::RUBY] if force_ruby_platform return valid_platforms if @platforms.empty? valid_platforms.select {|p| expanded_platforms.include?(GemHelpers.generic(p)) } diff --git a/lib/bundler/force_platform.rb b/lib/bundler/force_platform.rb new file mode 100644 index 0000000000..249a24ecd1 --- /dev/null +++ b/lib/bundler/force_platform.rb @@ -0,0 +1,18 @@ +# frozen_string_literal: true + +module Bundler + module ForcePlatform + private + + # The `:force_ruby_platform` value used by dependencies for resolution, and + # by locked specifications for materialization is `false` by default, except + # for TruffleRuby. TruffleRuby generally needs to force the RUBY platform + # variant unless the name is explicitly allowlisted. + + def default_force_ruby_platform + return false unless RUBY_ENGINE == "truffleruby" + + !Gem::Platform::REUSE_AS_BINARY_ON_TRUFFLERUBY.include?(name) + end + end +end diff --git a/lib/bundler/lazy_specification.rb b/lib/bundler/lazy_specification.rb index 21a6f96f69..ca51691b5c 100644 --- a/lib/bundler/lazy_specification.rb +++ b/lib/bundler/lazy_specification.rb @@ -1,8 +1,11 @@ # frozen_string_literal: true +require_relative "force_platform" + module Bundler class LazySpecification include MatchPlatform + include ForcePlatform attr_reader :name, :version, :dependencies, :platform attr_accessor :source, :remote, :force_ruby_platform @@ -14,6 +17,7 @@ module Bundler @platform = platform || Gem::Platform::RUBY @source = source @specification = nil + @force_ruby_platform = default_force_ruby_platform end def full_name diff --git a/lib/bundler/man/bundle-gem.1 b/lib/bundler/man/bundle-gem.1 index efd7c8edbc..11cc002194 100644 --- a/lib/bundler/man/bundle-gem.1 +++ b/lib/bundler/man/bundle-gem.1 @@ -31,41 +31,32 @@ The generated project skeleton can be customized with OPTIONS, as explained belo . .SH "OPTIONS" . -.TP -\fB\-\-exe\fR or \fB\-b\fR or \fB\-\-bin\fR -Specify that Bundler should create a binary executable (as \fBexe/GEM_NAME\fR) in the generated rubygem project\. This binary will also be added to the \fBGEM_NAME\.gemspec\fR manifest\. This behavior is disabled by default\. +.IP "\(bu" 4 +\fB\-\-exe\fR or \fB\-b\fR or \fB\-\-bin\fR: Specify that Bundler should create a binary executable (as \fBexe/GEM_NAME\fR) in the generated rubygem project\. This binary will also be added to the \fBGEM_NAME\.gemspec\fR manifest\. This behavior is disabled by default\. . -.TP -\fB\-\-no\-exe\fR -Do not create a binary (overrides \fB\-\-exe\fR specified in the global config)\. +.IP "\(bu" 4 +\fB\-\-no\-exe\fR: Do not create a binary (overrides \fB\-\-exe\fR specified in the global config)\. . -.TP -\fB\-\-coc\fR -Add a \fBCODE_OF_CONDUCT\.md\fR file to the root of the generated project\. If this option is unspecified, an interactive prompt will be displayed and the answer will be saved in Bundler\'s global config for future \fBbundle gem\fR use\. +.IP "\(bu" 4 +\fB\-\-coc\fR: Add a \fBCODE_OF_CONDUCT\.md\fR file to the root of the generated project\. If this option is unspecified, an interactive prompt will be displayed and the answer will be saved in Bundler\'s global config for future \fBbundle gem\fR use\. . -.TP -\fB\-\-no\-coc\fR -Do not create a \fBCODE_OF_CONDUCT\.md\fR (overrides \fB\-\-coc\fR specified in the global config)\. +.IP "\(bu" 4 +\fB\-\-no\-coc\fR: Do not create a \fBCODE_OF_CONDUCT\.md\fR (overrides \fB\-\-coc\fR specified in the global config)\. . -.TP -\fB\-\-ext=c\fR -Add boilerplate for C extension code to the generated project\. This behavior is disabled by default\. +.IP "\(bu" 4 +\fB\-\-ext=c\fR, \fB\-\-ext=rust\fR Add boilerplate for C or Rust (currently magnus \fIhttps://docs\.rs/magnus\fR based) extension code to the generated project\. This behavior is disabled by default\. . -.TP -\fB\-\-no\-ext\fR -Do not add C extension code (overrides \fB\-\-ext\fR specified in the global config)\. +.IP "\(bu" 4 +\fB\-\-no\-ext\fR: Do not add extension code (overrides \fB\-\-ext\fR specified in the global config)\. . -.TP -\fB\-\-mit\fR -Add an MIT license to a \fBLICENSE\.txt\fR file in the root of the generated project\. Your name from the global git config is used for the copyright statement\. If this option is unspecified, an interactive prompt will be displayed and the answer will be saved in Bundler\'s global config for future \fBbundle gem\fR use\. +.IP "\(bu" 4 +\fB\-\-mit\fR: Add an MIT license to a \fBLICENSE\.txt\fR file in the root of the generated project\. Your name from the global git config is used for the copyright statement\. If this option is unspecified, an interactive prompt will be displayed and the answer will be saved in Bundler\'s global config for future \fBbundle gem\fR use\. . -.TP -\fB\-\-no\-mit\fR -Do not create a \fBLICENSE\.txt\fR (overrides \fB\-\-mit\fR specified in the global config)\. +.IP "\(bu" 4 +\fB\-\-no\-mit\fR: Do not create a \fBLICENSE\.txt\fR (overrides \fB\-\-mit\fR specified in the global config)\. . -.TP -\fB\-t\fR, \fB\-\-test=minitest\fR, \fB\-\-test=rspec\fR, \fB\-\-test=test\-unit\fR -Specify the test framework that Bundler should use when generating the project\. Acceptable values are \fBminitest\fR, \fBrspec\fR and \fBtest\-unit\fR\. The \fBGEM_NAME\.gemspec\fR will be configured and a skeleton test/spec directory will be created based on this option\. Given no option is specified: +.IP "\(bu" 4 +\fB\-t\fR, \fB\-\-test=minitest\fR, \fB\-\-test=rspec\fR, \fB\-\-test=test\-unit\fR: Specify the test framework that Bundler should use when generating the project\. Acceptable values are \fBminitest\fR, \fBrspec\fR and \fBtest\-unit\fR\. The \fBGEM_NAME\.gemspec\fR will be configured and a skeleton test/spec directory will be created based on this option\. Given no option is specified: . .IP When Bundler is configured to generate tests, this defaults to Bundler\'s global config setting \fBgem\.test\fR\. @@ -76,9 +67,8 @@ When Bundler is configured to not generate tests, an interactive prompt will be .IP When Bundler is unconfigured, an interactive prompt will be displayed and the answer will be saved in Bundler\'s global config for future \fBbundle gem\fR use\. . -.TP -\fB\-\-ci\fR, \fB\-\-ci=github\fR, \fB\-\-ci=gitlab\fR, \fB\-\-ci=circle\fR -Specify the continuous integration service that Bundler should use when generating the project\. Acceptable values are \fBgithub\fR, \fBgitlab\fR and \fBcircle\fR\. A configuration file will be generated in the project directory\. Given no option is specified: +.IP "\(bu" 4 +\fB\-\-ci\fR, \fB\-\-ci=github\fR, \fB\-\-ci=gitlab\fR, \fB\-\-ci=circle\fR: Specify the continuous integration service that Bundler should use when generating the project\. Acceptable values are \fBgithub\fR, \fBgitlab\fR and \fBcircle\fR\. A configuration file will be generated in the project directory\. Given no option is specified: . .IP When Bundler is configured to generate CI files, this defaults to Bundler\'s global config setting \fBgem\.ci\fR\. @@ -89,9 +79,8 @@ When Bundler is configured to not generate CI files, an interactive prompt will .IP When Bundler is unconfigured, an interactive prompt will be displayed and the answer will be saved in Bundler\'s global config for future \fBbundle gem\fR use\. . -.TP -\fB\-\-linter\fR, \fB\-\-linter=rubocop\fR, \fB\-\-linter=standard\fR -Specify the linter and code formatter that Bundler should add to the project\'s development dependencies\. Acceptable values are \fBrubocop\fR and \fBstandard\fR\. A configuration file will be generated in the project directory\. Given no option is specified: +.IP "\(bu" 4 +\fB\-\-linter\fR, \fB\-\-linter=rubocop\fR, \fB\-\-linter=standard\fR: Specify the linter and code formatter that Bundler should add to the project\'s development dependencies\. Acceptable values are \fBrubocop\fR and \fBstandard\fR\. A configuration file will be generated in the project directory\. Given no option is specified: . .IP When Bundler is configured to add a linter, this defaults to Bundler\'s global config setting \fBgem\.linter\fR\. @@ -102,9 +91,10 @@ When Bundler is configured not to add a linter, an interactive prompt will be di .IP When Bundler is unconfigured, an interactive prompt will be displayed and the answer will be saved in Bundler\'s global config for future \fBbundle gem\fR use\. . -.TP -\fB\-e\fR, \fB\-\-edit[=EDITOR]\fR -Open the resulting GEM_NAME\.gemspec in EDITOR, or the default editor if not specified\. The default is \fB$BUNDLER_EDITOR\fR, \fB$VISUAL\fR, or \fB$EDITOR\fR\. +.IP "\(bu" 4 +\fB\-e\fR, \fB\-\-edit[=EDITOR]\fR: Open the resulting GEM_NAME\.gemspec in EDITOR, or the default editor if not specified\. The default is \fB$BUNDLER_EDITOR\fR, \fB$VISUAL\fR, or \fB$EDITOR\fR\. +. +.IP "" 0 . .SH "SEE ALSO" . diff --git a/lib/bundler/man/bundle-gem.1.ronn b/lib/bundler/man/bundle-gem.1.ronn index 96966107e3..46fa2f179f 100644 --- a/lib/bundler/man/bundle-gem.1.ronn +++ b/lib/bundler/man/bundle-gem.1.ronn @@ -41,12 +41,12 @@ configuration file using the following names: Do not create a `CODE_OF_CONDUCT.md` (overrides `--coc` specified in the global config). -* `--ext=c`: - Add boilerplate for C extension code to the generated project. This behavior +* `--ext=c`, `--ext=rust` + Add boilerplate for C or Rust (currently [magnus](https://docs.rs/magnus) based) extension code to the generated project. This behavior is disabled by default. * `--no-ext`: - Do not add C extension code (overrides `--ext` specified in the global + Do not add extension code (overrides `--ext` specified in the global config). * `--mit`: diff --git a/lib/bundler/resolver.rb b/lib/bundler/resolver.rb index b654cb819d..a2d4820d58 100644 --- a/lib/bundler/resolver.rb +++ b/lib/bundler/resolver.rb @@ -27,6 +27,17 @@ module Bundler remove_from_candidates(spec) end + @requirements = requirements + @packages = packages + + root, logger = setup_solver + + Bundler.ui.info "Resolving dependencies...", true + + solve_versions(:root => root, :logger => logger) + end + + def setup_solver root = Resolver::Root.new(name_for_explicit_dependency_source) root_version = Resolver::Candidate.new(0) @@ -42,24 +53,27 @@ module Bundler end end - root_dependencies = prepare_dependencies(requirements, packages) + root_dependencies = prepare_dependencies(@requirements, @packages) @cached_dependencies = Hash.new do |dependencies, package| dependencies[package] = if package.root? { root_version => root_dependencies } else Hash.new do |versions, version| - versions[version] = to_dependency_hash(version.dependencies, packages) + versions[version] = to_dependency_hash(version.dependencies, @packages) end end end logger = Bundler::UI::Shell.new logger.level = debug? ? "debug" : "warn" + + [root, logger] + end + + def solve_versions(root:, logger:) solver = PubGrub::VersionSolver.new(:source => self, :root => root, :logger => logger) - before_resolution result = solver.solve - after_resolution result.map {|package, version| version.to_specs(package) }.flatten.uniq rescue PubGrub::SolveFailure => e incompatibility = e.incompatibility @@ -82,8 +96,15 @@ module Bundler end end + names_to_unlock.uniq! + if names_to_unlock.any? + Bundler.ui.debug "Found conflicts with locked dependencies. Retrying with #{names_to_unlock.join(", ")} unlocked...", true + @base.unlock_names(names_to_unlock) + + root, logger = setup_solver + retry end @@ -144,14 +165,6 @@ module Bundler false end - def before_resolution - Bundler.ui.info "Resolving dependencies...", debug? - end - - def after_resolution - Bundler.ui.info "" - end - def incompatibilities_for(package, version) package_deps = @cached_dependencies[package] sorted_versions = @sorted_versions[package] @@ -202,7 +215,7 @@ module Bundler def all_versions_for(package) name = package.name - results = @base[name] + @all_specs[name] + results = (@base[name] + @all_specs[name]).uniq(&:full_name) locked_requirement = base_requirements[name] results = filter_matching_specs(results, locked_requirement) if locked_requirement diff --git a/lib/bundler/rubygems_ext.rb b/lib/bundler/rubygems_ext.rb index 705c4c8458..0252e1a81a 100644 --- a/lib/bundler/rubygems_ext.rb +++ b/lib/bundler/rubygems_ext.rb @@ -16,6 +16,7 @@ require "rubygems/specification" require "rubygems/source" require_relative "match_metadata" +require_relative "force_platform" require_relative "match_platform" # Cherry-pick fixes to `Gem.ruby_version` to be useful for modern Bundler @@ -153,12 +154,16 @@ module Gem end class Dependency + include ::Bundler::ForcePlatform + attr_accessor :source, :groups alias_method :eql?, :== def force_ruby_platform - false + return @force_ruby_platform if defined?(@force_ruby_platform) && !@force_ruby_platform.nil? + + @force_ruby_platform = default_force_ruby_platform end def encode_with(coder) @@ -277,6 +282,10 @@ module Gem without_gnu_nor_abi_modifiers end end + + if RUBY_ENGINE == "truffleruby" && !defined?(REUSE_AS_BINARY_ON_TRUFFLERUBY) + REUSE_AS_BINARY_ON_TRUFFLERUBY = %w[libv8 libv8-node sorbet-static].freeze + end end Platform.singleton_class.module_eval do diff --git a/lib/bundler/source/git/git_proxy.rb b/lib/bundler/source/git/git_proxy.rb index 31b3107c9e..7133e260a0 100644 --- a/lib/bundler/source/git/git_proxy.rb +++ b/lib/bundler/source/git/git_proxy.rb @@ -176,37 +176,32 @@ module Bundler @depth = if !supports_fetching_unreachable_refs? nil - elsif not_pinned? + elsif not_pinned? || pinned_to_full_sha? 1 elsif ref.include?("~") parsed_depth = ref.split("~").last parsed_depth.to_i + 1 - elsif abbreviated_ref? - nil - else - 1 end end def refspec - if fully_qualified_ref - "#{fully_qualified_ref}:#{fully_qualified_ref}" - elsif ref.include?("~") - parsed_ref = ref.split("~").first - "#{parsed_ref}:#{parsed_ref}" + return ref if pinned_to_full_sha? + + ref_to_fetch = @revision || fully_qualified_ref + + ref_to_fetch ||= if ref.include?("~") + ref.split("~").first elsif ref.start_with?("refs/") - "#{ref}:#{ref}" - elsif abbreviated_ref? - nil - else ref + else + "refs/*" end + + "#{ref_to_fetch}:#{ref_to_fetch}" end def fully_qualified_ref - return @fully_qualified_ref if defined?(@fully_qualified_ref) - - @fully_qualified_ref = if branch + if branch "refs/heads/#{branch}" elsif tag "refs/tags/#{tag}" @@ -219,8 +214,8 @@ module Bundler branch || tag || ref.nil? end - def abbreviated_ref? - ref =~ /\A\h+\z/ && ref !~ /\A\h{40}\z/ + def pinned_to_full_sha? + ref =~ /\A\h{40}\z/ end def legacy_locked_revision? diff --git a/lib/bundler/spec_set.rb b/lib/bundler/spec_set.rb index a3d9218593..7478bd9ca2 100644 --- a/lib/bundler/spec_set.rb +++ b/lib/bundler/spec_set.rb @@ -190,12 +190,10 @@ module Bundler def specs_for_dependency(dep, platform) specs_for_name = lookup[dep.name] - if platform.nil? - matching_specs = specs_for_name.map {|s| s.materialize_for_installation if Gem::Platform.match_spec?(s) }.compact - GemHelpers.sort_best_platform_match(matching_specs, Bundler.local_platform) - else - GemHelpers.select_best_platform_match(specs_for_name, dep.force_ruby_platform ? Gem::Platform::RUBY : platform) - end + target_platform = dep.force_ruby_platform ? Gem::Platform::RUBY : (platform || Bundler.local_platform) + matching_specs = GemHelpers.select_best_platform_match(specs_for_name, target_platform) + matching_specs.map!(&:materialize_for_installation).compact! if platform.nil? + matching_specs end def tsort_each_child(s) diff --git a/lib/bundler/templates/newgem/Cargo.toml.tt b/lib/bundler/templates/newgem/Cargo.toml.tt new file mode 100644 index 0000000000..7be7550cce --- /dev/null +++ b/lib/bundler/templates/newgem/Cargo.toml.tt @@ -0,0 +1,7 @@ +# This Cargo.toml is here to let externals tools (IDEs, etc.) know that this is +# a Rust project. Your extensions depedencies should be added to the Cargo.toml +# in the ext/ directory. + +[workspace] +members = ["./ext/<%= config[:name] %>"] +resolver = "2" diff --git a/lib/bundler/templates/newgem/Gemfile.tt b/lib/bundler/templates/newgem/Gemfile.tt index de82a63c5f..41c95677a3 100644 --- a/lib/bundler/templates/newgem/Gemfile.tt +++ b/lib/bundler/templates/newgem/Gemfile.tt @@ -9,6 +9,9 @@ gem "rake", "~> 13.0" <%- if config[:ext] -%> gem "rake-compiler" +<%- if config[:ext] == 'rust' -%> +gem "rb_sys" +<%- end -%> <%- end -%> <%- if config[:test] -%> diff --git a/lib/bundler/templates/newgem/README.md.tt b/lib/bundler/templates/newgem/README.md.tt index a60c7967ec..20eaac8a62 100644 --- a/lib/bundler/templates/newgem/README.md.tt +++ b/lib/bundler/templates/newgem/README.md.tt @@ -1,18 +1,20 @@ # <%= config[:constant_name] %> -Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/<%= config[:namespaced_path] %>`. To experiment with that code, run `bin/console` for an interactive prompt. +TODO: Delete this and the text below, and describe your gem -TODO: Delete this and the text above, and describe your gem +Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/<%= config[:namespaced_path] %>`. To experiment with that code, run `bin/console` for an interactive prompt. ## Installation +TODO: Replace `UPDATE_WITH_YOUR_GEM_NAME_PRIOR_TO_RELEASE_TO_RUBYGEMS_ORG` with your gem name right after releasing it to RubyGems.org. Please do not do it earlier due to security reasons. Alternatively, replace this section with instructions to install your gem from git if you don't plan to release to RubyGems.org. + Install the gem and add to the application's Gemfile by executing: - $ bundle add <%= config[:name] %> + $ bundle add UPDATE_WITH_YOUR_GEM_NAME_PRIOR_TO_RELEASE_TO_RUBYGEMS_ORG If bundler is not being used to manage dependencies, install the gem by executing: - $ gem install <%= config[:name] %> + $ gem install UPDATE_WITH_YOUR_GEM_NAME_PRIOR_TO_RELEASE_TO_RUBYGEMS_ORG ## Usage diff --git a/lib/bundler/templates/newgem/Rakefile.tt b/lib/bundler/templates/newgem/Rakefile.tt index b02ada9b6c..ac14545126 100644 --- a/lib/bundler/templates/newgem/Rakefile.tt +++ b/lib/bundler/templates/newgem/Rakefile.tt @@ -39,7 +39,8 @@ require "standard/rake" <% end -%> <% if config[:ext] -%> -<% default_task_names.unshift(:clobber, :compile) -%> +<% default_task_names.unshift(:compile) -%> +<% default_task_names.unshift(:clobber) unless config[:ext] == 'rust' -%> require "rake/extensiontask" task build: :compile diff --git a/lib/bundler/templates/newgem/circleci/config.yml.tt b/lib/bundler/templates/newgem/circleci/config.yml.tt index 79fd0dcc0f..f40f029bf1 100644 --- a/lib/bundler/templates/newgem/circleci/config.yml.tt +++ b/lib/bundler/templates/newgem/circleci/config.yml.tt @@ -3,8 +3,20 @@ jobs: build: docker: - image: ruby:<%= RUBY_VERSION %> +<%- if config[:ext] == 'rust' -%> + environment: + RB_SYS_FORCE_INSTALL_RUST_TOOLCHAIN: 'true' +<%- end -%> steps: - checkout +<%- if config[:ext] == 'rust' -%> + - run: + name: Install Rust/Cargo dependencies + command: apt-get update && apt-get install -y clang + - run: + name: Install a RubyGems version that can compile rust extensions + command: gem update --system '<%= ::Gem.rubygems_version %>' +<%- end -%> - run: name: Run the default task command: | diff --git a/lib/bundler/templates/newgem/ext/newgem/Cargo.toml.tt b/lib/bundler/templates/newgem/ext/newgem/Cargo.toml.tt new file mode 100644 index 0000000000..4b6e9587f7 --- /dev/null +++ b/lib/bundler/templates/newgem/ext/newgem/Cargo.toml.tt @@ -0,0 +1,15 @@ +[package] +name = <%= config[:name].inspect %> +version = "0.1.0" +edition = "2021" +authors = ["<%= config[:author] %> <<%= config[:email] %>>"] +<%- if config[:mit] -%> +license = "MIT" +<%- end -%> +publish = false + +[lib] +crate-type = ["cdylib"] + +[dependencies] +magnus = { version = "0.4" } diff --git a/lib/bundler/templates/newgem/ext/newgem/extconf.rb.tt b/lib/bundler/templates/newgem/ext/newgem/extconf-c.rb.tt index e918063ddf..e918063ddf 100644 --- a/lib/bundler/templates/newgem/ext/newgem/extconf.rb.tt +++ b/lib/bundler/templates/newgem/ext/newgem/extconf-c.rb.tt diff --git a/lib/bundler/templates/newgem/ext/newgem/extconf-rust.rb.tt b/lib/bundler/templates/newgem/ext/newgem/extconf-rust.rb.tt new file mode 100644 index 0000000000..e24566a17a --- /dev/null +++ b/lib/bundler/templates/newgem/ext/newgem/extconf-rust.rb.tt @@ -0,0 +1,6 @@ +# frozen_string_literal: true + +require "mkmf" +require "rb_sys/mkmf" + +create_rust_makefile(<%= config[:makefile_path].inspect %>) diff --git a/lib/bundler/templates/newgem/ext/newgem/src/lib.rs.tt b/lib/bundler/templates/newgem/ext/newgem/src/lib.rs.tt new file mode 100644 index 0000000000..b311283997 --- /dev/null +++ b/lib/bundler/templates/newgem/ext/newgem/src/lib.rs.tt @@ -0,0 +1,12 @@ +use magnus::{define_module, function, prelude::*, Error}; + +fn hello(subject: String) -> String { + format!("Hello from Rust, {}!", subject) +} + +#[magnus::init] +fn init() -> Result<(), Error> { + let module = <%= config[:constant_array].map {|c| "define_module(#{c.dump})?"}.join(".") %>; + module.define_singleton_method("hello", function!(hello, 1))?; + Ok(()) +} diff --git a/lib/bundler/templates/newgem/github/workflows/main.yml.tt b/lib/bundler/templates/newgem/github/workflows/main.yml.tt index 1ff4b58b7b..d4021980b4 100644 --- a/lib/bundler/templates/newgem/github/workflows/main.yml.tt +++ b/lib/bundler/templates/newgem/github/workflows/main.yml.tt @@ -18,10 +18,20 @@ jobs: steps: - uses: actions/checkout@v3 +<%- if config[:ext] == 'rust' -%> + - name: Set up Ruby & Rust + uses: oxidize-rb/actions/setup-ruby-and-rust@main + with: + ruby-version: ${{ matrix.ruby }} + bundler-cache: true + cargo-cache: true + rubygems: '<%= ::Gem.rubygems_version %>' +<%- else -%> - name: Set up Ruby uses: ruby/setup-ruby@v1 with: ruby-version: ${{ matrix.ruby }} bundler-cache: true +<%- end -%> - name: Run the default task run: bundle exec rake diff --git a/lib/bundler/templates/newgem/gitignore.tt b/lib/bundler/templates/newgem/gitignore.tt index b1c9f9986c..9b40ba5a58 100644 --- a/lib/bundler/templates/newgem/gitignore.tt +++ b/lib/bundler/templates/newgem/gitignore.tt @@ -12,6 +12,9 @@ *.o *.a mkmf.log +<%- if config[:ext] == 'rust' -%> +target/ +<%- end -%> <%- end -%> <%- if config[:test] == "rspec" -%> diff --git a/lib/bundler/templates/newgem/gitlab-ci.yml.tt b/lib/bundler/templates/newgem/gitlab-ci.yml.tt index 42e00392de..d2e1f33736 100644 --- a/lib/bundler/templates/newgem/gitlab-ci.yml.tt +++ b/lib/bundler/templates/newgem/gitlab-ci.yml.tt @@ -2,9 +2,17 @@ default: image: ruby:<%= RUBY_VERSION %> before_script: +<%- if config[:ext] == 'rust' -%> + - apt-get update && apt-get install -y clang + - gem update --system '<%= ::Gem.rubygems_version %>' +<%- end -%> - gem install bundler -v <%= Bundler::VERSION %> - bundle install example_job: +<%- if config[:ext] == 'rust' -%> + variables: + RB_SYS_FORCE_INSTALL_RUST_TOOLCHAIN: 'true' +<%- end -%> script: - bundle exec rake diff --git a/lib/bundler/templates/newgem/newgem.gemspec.tt b/lib/bundler/templates/newgem/newgem.gemspec.tt index a03dcc8bc2..e35a121245 100644 --- a/lib/bundler/templates/newgem/newgem.gemspec.tt +++ b/lib/bundler/templates/newgem/newgem.gemspec.tt @@ -15,6 +15,9 @@ Gem::Specification.new do |spec| spec.license = "MIT" <%- end -%> spec.required_ruby_version = ">= <%= config[:required_ruby_version] %>" +<%- if config[:ext] == 'rust' -%> + spec.required_rubygems_version = ">= <%= config[:rust_builder_required_rubygems_version] %>" +<%- end -%> spec.metadata["allowed_push_host"] = "TODO: Set to your gem server 'https://example.com'" @@ -32,9 +35,12 @@ Gem::Specification.new do |spec| spec.bindir = "exe" spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) } spec.require_paths = ["lib"] -<%- if config[:ext] -%> +<%- if config[:ext] == 'c' -%> spec.extensions = ["ext/<%= config[:underscored_name] %>/extconf.rb"] <%- end -%> +<%- if config[:ext] == 'rust' -%> + spec.extensions = ["ext/<%= config[:underscored_name] %>/Cargo.toml"] +<%- end -%> # Uncomment to register a new dependency of your gem # spec.add_dependency "example-gem", "~> 1.0" diff --git a/lib/bundler/version.rb b/lib/bundler/version.rb index a2a244c220..29f78a03c4 100644 --- a/lib/bundler/version.rb +++ b/lib/bundler/version.rb @@ -1,7 +1,7 @@ # frozen_string_literal: false module Bundler - VERSION = "2.4.0.dev".freeze + VERSION = "2.4.0".freeze def self.bundler_major_version @bundler_major_version ||= VERSION.split(".").first.to_i |