diff --git a/bundler/lib/bundler/cli.rb b/bundler/lib/bundler/cli.rb index 3395e7455684..9c164b09f4ee 100644 --- a/bundler/lib/bundler/cli.rb +++ b/bundler/lib/bundler/cli.rb @@ -10,6 +10,7 @@ class CLI < Thor 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 COMMAND_ALIASES = { "check" => "c", @@ -22,6 +23,8 @@ class CLI < Thor }.freeze def self.start(*) + check_deprecated_ext_option(ARGV) if ARGV.include?("--ext") + super ensure Bundler::SharedHelpers.print_major_deprecations! @@ -576,7 +579,7 @@ def viz method_option :edit, :type => :string, :aliases => "-e", :required => false, :banner => "EDITOR", :lazy_default => [ENV["BUNDLER_EDITOR"], ENV["VISUAL"], ENV["EDITOR"]].find {|e| !e.nil? && !e.empty? }, :desc => "Open generated gemspec in the specified editor (defaults to $EDITOR or $BUNDLER_EDITOR)" - method_option :ext, :type => :boolean, :default => false, :desc => "Generate the boilerplate for C extension code" + method_option :ext, :type => :string, :desc => "Generate the boilerplate for C extension code.", :enum => EXTENSIONS method_option :git, :type => :boolean, :default => true, :desc => "Initialize a git repo inside your library." method_option :mit, :type => :boolean, :desc => "Generate an MIT license file. Set a default with `bundle config set --global gem.mit true`." method_option :rubocop, :type => :boolean, :desc => "Add rubocop to the generated Rakefile and gemspec. Set a default with `bundle config set --global gem.rubocop true`." @@ -755,6 +758,38 @@ def self.reformatted_help_args(args) end end + def self.check_deprecated_ext_option(arguments) + # 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." + arguments[arguments.index("--ext")] = "--ext=c" + end + end + + def self.deprecated_ext_value?(arguments) + index = arguments.index("--ext") + next_argument = arguments[index+1] + + # it is ok when --ext is followed with valid extension value + # for example `bundle gem hello --ext c` + return false if EXTENSIONS.include?(next_argument) + + # deprecated call when --ext is called with no value in last position + # for example `bundle gem hello_gem --ext` + return true if next_argument.nil? + + # deprecated call when --ext is followed by other parameter + # for example `bundle gem --ext --no-ci hello_gem` + return true if next_argument.start_with?("-") + + # deprecated call when --ext is followed by gem name + # for example `bundle gem --ext hello_gem` + return true if next_argument + + false + end + private # Automatically invoke `bundle install` and resume if diff --git a/bundler/lib/bundler/cli/gem.rb b/bundler/lib/bundler/cli/gem.rb index 135bfde03840..584b28d67d48 100644 --- a/bundler/lib/bundler/cli/gem.rb +++ b/bundler/lib/bundler/cli/gem.rb @@ -15,7 +15,7 @@ class CLI::Gem "test-unit" => "3.0", }.freeze - attr_reader :options, :gem_name, :thor, :name, :target + attr_reader :options, :gem_name, :thor, :name, :target, :extension def initialize(options, gem_name, thor) @options = options @@ -28,7 +28,9 @@ def initialize(options, gem_name, thor) @name = @gem_name @target = SharedHelpers.pwd.join(gem_name) - validate_ext_name if options[:ext] + @extension = options[:ext] + + validate_ext_name if @extension end def run @@ -64,7 +66,7 @@ def run :author => git_author_name.empty? ? "TODO: Write your name" : git_author_name, :email => git_user_email.empty? ? "TODO: Write your email address" : git_user_email, :test => options[:test], - :ext => options[:ext], + :ext => extension, :exe => options[:exe], :bundler_version => bundler_dependency_version, :git => use_git, @@ -188,7 +190,7 @@ def run templates.merge!("exe/newgem.tt" => "exe/#{name}") if config[:exe] - if options[:ext] + if extension templates.merge!( "ext/newgem/extconf.rb.tt" => "ext/#{name}/extconf.rb", "ext/newgem/newgem.h.tt" => "ext/#{name}/#{underscored_name}.h", diff --git a/bundler/lib/bundler/man/bundle-gem.1 b/bundler/lib/bundler/man/bundle-gem.1 index 8a82dfdd2a00..e32a03daf409 100644 --- a/bundler/lib/bundler/man/bundle-gem.1 +++ b/bundler/lib/bundler/man/bundle-gem.1 @@ -48,7 +48,7 @@ Add a \fBCODE_OF_CONDUCT\.md\fR file to the root of the generated project\. If t Do not create a \fBCODE_OF_CONDUCT\.md\fR (overrides \fB\-\-coc\fR specified in the global config)\. . .TP -\fB\-\-ext\fR +\fB\-\-ext=c\fR Add boilerplate for C extension code to the generated project\. This behavior is disabled by default\. . .TP diff --git a/bundler/lib/bundler/man/bundle-gem.1.ronn b/bundler/lib/bundler/man/bundle-gem.1.ronn index 61c741fb24f6..6169175f3c04 100644 --- a/bundler/lib/bundler/man/bundle-gem.1.ronn +++ b/bundler/lib/bundler/man/bundle-gem.1.ronn @@ -41,7 +41,7 @@ configuration file using the following names: Do not create a `CODE_OF_CONDUCT.md` (overrides `--coc` specified in the global config). -* `--ext`: +* `--ext=c`: Add boilerplate for C extension code to the generated project. This behavior is disabled by default. diff --git a/bundler/spec/commands/newgem_spec.rb b/bundler/spec/commands/newgem_spec.rb index 55a04b69c59f..c4e8b3a6e766 100644 --- a/bundler/spec/commands/newgem_spec.rb +++ b/bundler/spec/commands/newgem_spec.rb @@ -312,28 +312,28 @@ def bundle_exec_standardrb it "has no rubocop offenses when using --ext and --linter=rubocop flag", :readline do skip "ruby_core has an 'ast.rb' file that gets in the middle and breaks this spec" if ruby_core? - bundle "gem #{gem_name} --ext --linter=rubocop" + bundle "gem #{gem_name} --ext=c --linter=rubocop" bundle_exec_rubocop expect(last_command).to be_success end it "has no rubocop offenses when using --ext, --test=minitest, and --linter=rubocop flag", :readline do skip "ruby_core has an 'ast.rb' file that gets in the middle and breaks this spec" if ruby_core? - bundle "gem #{gem_name} --ext --test=minitest --linter=rubocop" + bundle "gem #{gem_name} --ext=c --test=minitest --linter=rubocop" bundle_exec_rubocop expect(last_command).to be_success end it "has no rubocop offenses when using --ext, --test=rspec, and --linter=rubocop flag", :readline do skip "ruby_core has an 'ast.rb' file that gets in the middle and breaks this spec" if ruby_core? - bundle "gem #{gem_name} --ext --test=rspec --linter=rubocop" + bundle "gem #{gem_name} --ext=c --test=rspec --linter=rubocop" bundle_exec_rubocop expect(last_command).to be_success end it "has no rubocop offenses when using --ext, --ext=test-unit, and --linter=rubocop flag", :readline do skip "ruby_core has an 'ast.rb' file that gets in the middle and breaks this spec" if ruby_core? - bundle "gem #{gem_name} --ext --test=test-unit --linter=rubocop" + bundle "gem #{gem_name} --ext=c --test=test-unit --linter=rubocop" bundle_exec_rubocop expect(last_command).to be_success end @@ -1322,13 +1322,32 @@ def create_temporary_dir(dir) include_examples "generating a gem" - context "--ext parameter set" do - let(:flags) { "--ext" } + context "--ext parameter with no value" do + context "is deprecated", :bundler => "< 3" do + it "prints deprecation when used after gem name" do + bundle ["gem", "--ext", gem_name].compact.join(" ") + expect(err).to include "[DEPRECATED] Option `--ext` without explicit value is deprecated." + expect(bundled_app("#{gem_name}/ext/#{gem_name}/#{gem_name}.c")).to exist + end + + it "prints deprecation when used before gem name" do + bundle ["gem", gem_name, "--ext"].compact.join(" ") + expect(bundled_app("#{gem_name}/ext/#{gem_name}/#{gem_name}.c")).to exist + end + end + end + + context "--ext parameter set with C" do + let(:flags) { "--ext=c" } before do bundle ["gem", gem_name, flags].compact.join(" ") end + it "is not deprecated" do + expect(err).not_to include "[DEPRECATED] Option `--ext` without explicit value is deprecated." + end + it "builds ext skeleton" do expect(bundled_app("#{gem_name}/ext/#{gem_name}/extconf.rb")).to exist expect(bundled_app("#{gem_name}/ext/#{gem_name}/#{gem_name}.h")).to exist