Skip to content

Commit 59ad393

Browse files
Support thor install <uri> to install remote thor files
The previous code suggested that this was supported, but it was not really working as expected.
1 parent 8c9817d commit 59ad393

File tree

2 files changed

+70
-39
lines changed

2 files changed

+70
-39
lines changed

lib/thor/runner.rb

Lines changed: 27 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,6 @@
66
require "pathname"
77

88
class Thor::Runner < Thor #:nodoc:
9-
autoload :OpenURI, "open-uri"
10-
119
map "-T" => :list, "-i" => :install, "-u" => :update, "-v" => :version
1210

1311
def self.banner(command, all = false, subcommand = false)
@@ -48,22 +46,33 @@ def method_missing(meth, *args)
4846
def install(name) # rubocop:disable Metrics/MethodLength
4947
initialize_thorfiles
5048

51-
# If a directory name is provided as the argument, look for a 'main.thor'
52-
# command in said directory.
53-
begin
54-
if File.directory?(File.expand_path(name))
55-
base = File.join(name, "main.thor")
56-
package = :directory
57-
contents = open(base, &:read)
58-
else
59-
base = name
60-
package = :file
61-
contents = open(name, &:read)
49+
is_uri = name =~ %r{^https?\://}
50+
51+
if is_uri
52+
base = name
53+
package = :file
54+
require "open-uri"
55+
begin
56+
contents = URI.send(:open, name, &:read) # Using `send` for Ruby 2.4- support
57+
rescue OpenURI::HTTPError
58+
raise Error, "Error opening URI '#{name}'"
59+
end
60+
else
61+
# If a directory name is provided as the argument, look for a 'main.thor'
62+
# command in said directory.
63+
begin
64+
if File.directory?(File.expand_path(name))
65+
base = File.join(name, "main.thor")
66+
package = :directory
67+
contents = open(base, &:read)
68+
else
69+
base = name
70+
package = :file
71+
contents = open(name, &:read)
72+
end
73+
rescue Errno::ENOENT
74+
raise Error, "Error opening file '#{name}'"
6275
end
63-
rescue OpenURI::HTTPError
64-
raise Error, "Error opening URI '#{name}'"
65-
rescue Errno::ENOENT
66-
raise Error, "Error opening file '#{name}'"
6776
end
6877

6978
say "Your Thorfile contains:"
@@ -84,7 +93,7 @@ def install(name) # rubocop:disable Metrics/MethodLength
8493
as = basename if as.empty?
8594
end
8695

87-
location = if options[:relative] || name =~ %r{^https?://}
96+
location = if options[:relative] || is_uri
8897
name
8998
else
9099
File.expand_path(name)

spec/runner_spec.rb

Lines changed: 43 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -118,11 +118,11 @@ def when_no_thorfiles_exist
118118
end
119119

120120
describe "commands" do
121+
let(:location) { "#{File.dirname(__FILE__)}/fixtures/command.thor" }
121122
before do
122-
@location = "#{File.dirname(__FILE__)}/fixtures/command.thor"
123123
@original_yaml = {
124124
"random" => {
125-
:location => @location,
125+
:location => location,
126126
:filename => "4a33b894ffce85d7b412fc1b36f88fe0",
127127
:namespaces => %w(amazing)
128128
}
@@ -214,31 +214,53 @@ def when_no_thorfiles_exist
214214
end
215215

216216
describe "install/update" do
217-
before do
218-
allow(FileUtils).to receive(:mkdir_p)
219-
allow(FileUtils).to receive(:touch)
220-
allow(Thor::LineEditor).to receive(:readline).and_return("Y")
217+
context "with local thor files" do
218+
before do
219+
allow(FileUtils).to receive(:mkdir_p)
220+
allow(FileUtils).to receive(:touch)
221+
allow(Thor::LineEditor).to receive(:readline).and_return("Y")
222+
223+
path = File.join(Thor::Util.thor_root, Digest::MD5.hexdigest(location + "random"))
224+
expect(File).to receive(:open).with(path, "w")
225+
end
221226

222-
path = File.join(Thor::Util.thor_root, Digest::MD5.hexdigest(@location + "random"))
223-
expect(File).to receive(:open).with(path, "w")
224-
end
225227

226-
it "updates existing thor files" do
227-
path = File.join(Thor::Util.thor_root, @original_yaml["random"][:filename])
228-
if File.directory? path
229-
expect(FileUtils).to receive(:rm_rf).with(path)
230-
else
231-
expect(File).to receive(:delete).with(path)
228+
it "updates existing thor files" do
229+
path = File.join(Thor::Util.thor_root, @original_yaml["random"][:filename])
230+
if File.directory? path
231+
expect(FileUtils).to receive(:rm_rf).with(path)
232+
else
233+
expect(File).to receive(:delete).with(path)
234+
end
235+
silence_warnings do
236+
silence(:stdout) { Thor::Runner.start(%w(update random)) }
237+
end
232238
end
233-
silence_warnings do
234-
silence(:stdout) { Thor::Runner.start(%w(update random)) }
239+
240+
it "installs thor files" do
241+
ARGV.replace %W(install #{location})
242+
silence_warnings do
243+
silence(:stdout) { Thor::Runner.start }
244+
end
235245
end
236246
end
237247

238-
it "installs thor files" do
239-
ARGV.replace %W(install #{@location})
240-
silence_warnings do
241-
silence(:stdout) { Thor::Runner.start }
248+
context "with remote thor files" do
249+
let(:location) { "https://example.com/Thorfile" }
250+
251+
it "installs thor files" do
252+
allow(Thor::LineEditor).to receive(:readline).and_return("Y", "random")
253+
stub_request(:get, location).to_return(:body => "class Foo < Thor; end")
254+
path = File.join(Thor::Util.thor_root, Digest::MD5.hexdigest(location + "random"))
255+
expect(File).to receive(:open).with(path, "w")
256+
expect { silence(:stdout) { Thor::Runner.start(%W(install #{location})) } }.not_to raise_error
257+
end
258+
259+
it "shows proper errors" do
260+
expect(Thor::Runner).to receive :exit
261+
expect(URI).to receive(:open).with(location).and_raise(OpenURI::HTTPError.new("foo", StringIO.new))
262+
content = capture(:stderr) { Thor::Runner.start(%W(install #{location})) }
263+
expect(content).to include("Error opening URI '#{location}'")
242264
end
243265
end
244266
end

0 commit comments

Comments
 (0)