Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion lib/bundler/dsl.rb
Original file line number Diff line number Diff line change
Expand Up @@ -290,7 +290,7 @@ def add_dependency(name, version = nil, options = {})
@dependencies.delete(current)
elsif dep.gemspec_dev_dep?
return
elsif current.source != dep.source
elsif current.source.to_s != dep.source.to_s
raise GemfileError, "You cannot specify the same gem twice coming from different sources.\n" \
"You specified that #{name} (#{dep.requirement}) should come from " \
"#{current.source || "an unspecified source"} and #{dep.source}\n"
Expand Down
4 changes: 4 additions & 0 deletions lib/bundler/source/gemspec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ def initialize(options)
super
@gemspec = options["gemspec"]
end

def to_s
"gemspec at `#{@path}`"
end
end
end
end
2 changes: 2 additions & 0 deletions lib/bundler/source/path.rb
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ def to_s
"source at `#{@path}`"
end

alias_method :identifier, :to_s

alias_method :to_gemfile, :path

def hash
Expand Down
87 changes: 79 additions & 8 deletions lib/rubygems/commands/sources_command.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,14 @@ def initialize
options[:add] = value
end

add_option "--append SOURCE_URI", "Append source (can be used multiple times)" do |value, options|
options[:append] = value
end

add_option "-p", "--prepend SOURCE_URI", "Prepend source (can be used multiple times)" do |value, options|
options[:prepend] = value
end

add_option "-l", "--list", "List sources" do |value, options|
options[:list] = value
end
Expand All @@ -26,8 +34,7 @@ def initialize
options[:remove] = value
end

add_option "-c", "--clear-all",
"Remove all sources (clear the cache)" do |value, options|
add_option "-c", "--clear-all", "Remove all sources (clear the cache)" do |value, options|
options[:clear_all] = value
end

Expand Down Expand Up @@ -68,6 +75,60 @@ def add_source(source_uri) # :nodoc:
end
end

def append_source(source_uri) # :nodoc:
check_rubygems_https source_uri

source = Gem::Source.new source_uri

check_typo_squatting(source)

begin
source.load_specs :released
was_present = Gem.sources.include?(source)
Gem.sources.append source
Gem.configuration.write

if was_present
say "#{source_uri} moved to end of sources"
else
say "#{source_uri} added to sources"
end
rescue Gem::URI::Error, ArgumentError
say "#{source_uri} is not a URI"
terminate_interaction 1
rescue Gem::RemoteFetcher::FetchError => e
say "Error fetching #{Gem::Uri.redact(source.uri)}:\n\t#{e.message}"
terminate_interaction 1
end
end

def prepend_source(source_uri) # :nodoc:
check_rubygems_https source_uri

source = Gem::Source.new source_uri

check_typo_squatting(source)

begin
source.load_specs :released
was_present = Gem.sources.include?(source)
Gem.sources.prepend source
Gem.configuration.write

if was_present
say "#{source_uri} moved to top of sources"
else
say "#{source_uri} added to sources"
end
rescue Gem::URI::Error, ArgumentError
say "#{source_uri} is not a URI"
terminate_interaction 1
rescue Gem::RemoteFetcher::FetchError => e
say "Error fetching #{Gem::Uri.redact(source.uri)}:\n\t#{e.message}"
terminate_interaction 1
end
end

def check_typo_squatting(source)
if source.typo_squatting?("rubygems.org")
question = <<-QUESTION.chomp
Expand Down Expand Up @@ -147,14 +208,20 @@ def description # :nodoc:
of them in your list. https://rubygems.org is recommended as it brings the
protections of an SSL connection to gem downloads.

To add a source use the --add argument:
To add a private gem source use the --prepend argument to insert it before
the default source. This is usually the best place for private gem sources:

$ gem sources --add https://my.private.source
$ gem sources --prepend https://my.private.source
https://my.private.source added to sources

RubyGems will check to see if gems can be installed from the source given
before it is added.

To add or move a source after all other sources, use --append:

$ gem sources --append https://rubygems.org
https://rubygems.org moved to end of sources

To remove a source use the --remove argument:

$ gem sources --remove https://my.private.source/
Expand Down Expand Up @@ -182,6 +249,8 @@ def list # :nodoc:

def list? # :nodoc:
!(options[:add] ||
options[:prepend] ||
options[:append] ||
options[:clear_all] ||
options[:remove] ||
options[:update])
Expand All @@ -190,11 +259,13 @@ def list? # :nodoc:
def execute
clear_all if options[:clear_all]

source_uri = options[:add]
add_source source_uri if source_uri
add_source options[:add] if options[:add]

prepend_source options[:prepend] if options[:prepend]

append_source options[:append] if options[:append]

source_uri = options[:remove]
remove_source source_uri if source_uri
remove_source options[:remove] if options[:remove]

update if options[:update]

Expand Down
11 changes: 2 additions & 9 deletions lib/rubygems/exceptions.rb
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,8 @@ def initialize(unknown_command)
def self.attach_correctable
return if defined?(@attached)

if defined?(DidYouMean::SPELL_CHECKERS) && defined?(DidYouMean::Correctable)
if DidYouMean.respond_to?(:correct_error)
DidYouMean.correct_error(Gem::UnknownCommandError, Gem::UnknownCommandSpellChecker)
else
DidYouMean::SPELL_CHECKERS["Gem::UnknownCommandError"] =
Gem::UnknownCommandSpellChecker

prepend DidYouMean::Correctable
end
if defined?(DidYouMean) && DidYouMean.respond_to?(:correct_error)
DidYouMean.correct_error(Gem::UnknownCommandError, Gem::UnknownCommandSpellChecker)
end

@attached = true
Expand Down
36 changes: 36 additions & 0 deletions lib/rubygems/source_list.rb
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,42 @@ def <<(obj)
src
end

##
# Prepends +obj+ to the beginning of the source list which may be a Gem::Source, Gem::URI or URI
# Moves +obj+ to the beginning of the list if already present.
# String.

def prepend(obj)
src = case obj
when Gem::Source
obj
else
Gem::Source.new(obj)
end

@sources.delete(src) if @sources.include?(src)
@sources.unshift(src)
src
end

##
# Appends +obj+ to the end of the source list, moving it if already present.
# +obj+ may be a Gem::Source, Gem::URI or URI String.
# Moves +obj+ to the end of the list if already present.

def append(obj)
src = case obj
when Gem::Source
obj
else
Gem::Source.new(obj)
end

@sources.delete(src) if @sources.include?(src)
@sources << src
src
end

##
# Replaces this SourceList with the sources in +other+ See #<< for
# acceptable items in +other+.
Expand Down
24 changes: 24 additions & 0 deletions spec/bundler/commands/install_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -615,6 +615,30 @@
expect(err).to include("Two gemspec development dependencies have conflicting requirements on the same gem: rubocop (~> 1.36.0) and rubocop (~> 2.0). Bundler cannot continue.")
end

it "errors out if a gem is specified in a gemspec and in the Gemfile" do
gem = tmp("my-gem-1")

build_lib "rubocop", path: gem do |s|
s.add_development_dependency "rubocop", "~> 1.0"
end

build_repo4 do
build_gem "rubocop"
end

gemfile <<~G
source "https://gem.repo4"

gem "rubocop", :path => "#{gem}"
gemspec path: "#{gem}"
G

bundle :install, raise_on_error: false

expect(err).to include("There was an error parsing `Gemfile`: You cannot specify the same gem twice coming from different sources.")
expect(err).to include("You specified that rubocop (>= 0) should come from source at `#{gem}` and gemspec at `#{gem}`")
end

it "does not warn if a gem is added once in Gemfile and also inside a gemspec as a development dependency, with same requirements, and different sources" do
build_lib "my-gem", path: bundled_app do |s|
s.add_development_dependency "activesupport"
Expand Down
2 changes: 1 addition & 1 deletion test/rubygems/test_gem_command_manager.rb
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ def test_find_command_unknown_suggestions

message = "Unknown command pish".dup

if defined?(DidYouMean::SPELL_CHECKERS) && defined?(DidYouMean::Correctable)
if defined?(DidYouMean)
message << "\nDid you mean? \"push\""
end

Expand Down
Loading