Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support thor install <uri> to install remote thor files #787

Merged
merged 1 commit into from
Feb 8, 2023
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
45 changes: 27 additions & 18 deletions lib/thor/runner.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@
require "pathname"

class Thor::Runner < Thor #:nodoc:
autoload :OpenURI, "open-uri"

map "-T" => :list, "-i" => :install, "-u" => :update, "-v" => :version

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

# If a directory name is provided as the argument, look for a 'main.thor'
# command in said directory.
begin
if File.directory?(File.expand_path(name))
base = File.join(name, "main.thor")
package = :directory
contents = open(base, &:read)
else
base = name
package = :file
contents = open(name, &:read)
is_uri = name =~ %r{^https?\://}

if is_uri
base = name
package = :file
require "open-uri"
begin
contents = URI.send(:open, name, &:read) # Using `send` for Ruby 2.4- support
rescue OpenURI::HTTPError
raise Error, "Error opening URI '#{name}'"
end
else
# If a directory name is provided as the argument, look for a 'main.thor'
# command in said directory.
begin
if File.directory?(File.expand_path(name))
base = File.join(name, "main.thor")
package = :directory
contents = open(base, &:read)
else
base = name
package = :file
contents = open(name, &:read)
end
rescue Errno::ENOENT
raise Error, "Error opening file '#{name}'"
end
rescue OpenURI::HTTPError
raise Error, "Error opening URI '#{name}'"
rescue Errno::ENOENT
raise Error, "Error opening file '#{name}'"
end

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

location = if options[:relative] || name =~ %r{^https?://}
location = if options[:relative] || is_uri
name
else
File.expand_path(name)
Expand Down
65 changes: 43 additions & 22 deletions spec/runner_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -118,11 +118,11 @@ def when_no_thorfiles_exist
end

describe "commands" do
let(:location) { "#{File.dirname(__FILE__)}/fixtures/command.thor" }
before do
@location = "#{File.dirname(__FILE__)}/fixtures/command.thor"
@original_yaml = {
"random" => {
:location => @location,
:location => location,
:filename => "4a33b894ffce85d7b412fc1b36f88fe0",
:namespaces => %w(amazing)
}
Expand Down Expand Up @@ -214,31 +214,52 @@ def when_no_thorfiles_exist
end

describe "install/update" do
before do
allow(FileUtils).to receive(:mkdir_p)
allow(FileUtils).to receive(:touch)
allow(Thor::LineEditor).to receive(:readline).and_return("Y")

path = File.join(Thor::Util.thor_root, Digest::SHA256.hexdigest(@location + "random"))
expect(File).to receive(:open).with(path, "w")
end
context "with local thor files" do
before do
allow(FileUtils).to receive(:mkdir_p)
allow(FileUtils).to receive(:touch)
allow(Thor::LineEditor).to receive(:readline).and_return("Y")

path = File.join(Thor::Util.thor_root, Digest::SHA256.hexdigest(location + "random"))
expect(File).to receive(:open).with(path, "w")
end

it "updates existing thor files" do
path = File.join(Thor::Util.thor_root, @original_yaml["random"][:filename])
if File.directory? path
expect(FileUtils).to receive(:rm_rf).with(path)
else
expect(File).to receive(:delete).with(path)
it "updates existing thor files" do
path = File.join(Thor::Util.thor_root, @original_yaml["random"][:filename])
if File.directory? path
expect(FileUtils).to receive(:rm_rf).with(path)
else
expect(File).to receive(:delete).with(path)
end
silence_warnings do
silence(:stdout) { Thor::Runner.start(%w(update random)) }
end
end
silence_warnings do
silence(:stdout) { Thor::Runner.start(%w(update random)) }

it "installs thor files" do
ARGV.replace %W(install #{location})
silence_warnings do
silence(:stdout) { Thor::Runner.start }
end
end
end

it "installs thor files" do
ARGV.replace %W(install #{@location})
silence_warnings do
silence(:stdout) { Thor::Runner.start }
context "with remote thor files" do
let(:location) { "https://example.com/Thorfile" }

it "installs thor files" do
allow(Thor::LineEditor).to receive(:readline).and_return("Y", "random")
stub_request(:get, location).to_return(:body => "class Foo < Thor; end")
path = File.join(Thor::Util.thor_root, Digest::SHA256.hexdigest(location + "random"))
expect(File).to receive(:open).with(path, "w")
expect { silence(:stdout) { Thor::Runner.start(%W(install #{location})) } }.not_to raise_error
end

it "shows proper errors" do
expect(Thor::Runner).to receive :exit
expect(URI).to receive(:open).with(location).and_raise(OpenURI::HTTPError.new("foo", StringIO.new))
content = capture(:stderr) { Thor::Runner.start(%W(install #{location})) }
expect(content).to include("Error opening URI '#{location}'")
end
end
end
Expand Down