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

Check update automatically #13

Merged
merged 6 commits into from
Oct 9, 2017
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
3 changes: 3 additions & 0 deletions lib/one_gadget.rb
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,9 @@ def one_gadget(arg = nil, **options)
OneGadget.gadgets(**options)
end

require 'one_gadget/update'
OneGadget::Update.check!

require 'one_gadget/fetcher'
require 'one_gadget/helper'
require 'one_gadget/logger'
Expand Down
2 changes: 1 addition & 1 deletion lib/one_gadget/logger.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ module Logger
prep = ' ' * 12
message = msg.lines.map.with_index do |str, i|
next str if i.zero?
prep + str
str.strip.empty? ? str : prep + str
end
color = case severity
when 'WARN' then :warn
Expand Down
59 changes: 59 additions & 0 deletions lib/one_gadget/update.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
require 'fileutils'

require 'one_gadget/helper'
require 'one_gadget/logger'

module OneGadget
# For automatically check update.
module Update
# At least 7 days between check for new version.
FREQUENCY = 7 * 24 * 60 * 60
# Path to cache file.
CACHE_FILE = File.join(ENV['HOME'], '.cache', 'one_gadget', 'update').freeze

class << self
# Check if new releases have been drafted.
#
# @return [void]
def check!
return unless need_check?
OneGadget::Logger.info("Checking for new versions of OneGadget\n" \
"To disable this functionality, do\n$ echo never > #{CACHE_FILE}\n\n")
latest = Helper.latest_tag[1..-1] # remove 'v'
if Gem::Version.new(latest) <= Gem::Version.new(OneGadget::VERSION)
return OneGadget::Logger.info("You have the latest version of OneGadget (#{latest})!\n\n")
end

# show update message
msg = format("A newer version of OneGadget is available (%s --> %s).\n", OneGadget::VERSION, latest)
msg << "Update with: $ gem update one_gadget\n\n"
OneGadget::Logger.info(msg)
end

private

# check ~/.cache/one_gadget/update
def need_check?
cache = cache_file
return false if cache.nil? # cache file fails, no update check.
return false if IO.binread(cache).strip == 'never'
Time.now >= last_check + FREQUENCY
end

def last_check
cache = cache_file
return Time.now if cache.nil?
File.open(cache, &:mtime)
end

def cache_file
dir = File.dirname(CACHE_FILE)
FileUtils.mkdir_p(dir) unless File.directory?(dir)
IO.binwrite(CACHE_FILE, '') unless File.exist?(CACHE_FILE)
CACHE_FILE
rescue # prevent dir is not writable
return nil
end
end
end
end
70 changes: 70 additions & 0 deletions spec/update_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
require 'logger'

require 'one_gadget/update'
require 'one_gadget/version'

describe OneGadget::Update do
before(:all) do
# precent fail on CI
@hook_cache_file = lambda do |&block|
tmp = Dir::Tmpname.make_tmpname('/tmp/one_gadget/update', nil)
stub_const('OneGadget::Update::CACHE_FILE', tmp)
block.call(tmp)
end

@hook_logger = lambda do |&block|
# no method 'reopen' before ruby 2.3
org_logger = OneGadget::Logger.instance_variable_get(:@logger)
new_logger = ::Logger.new($stdout)
new_logger.formatter = org_logger.formatter
OneGadget::Logger.instance_variable_set(:@logger, new_logger)
block.call
OneGadget::Logger.instance_variable_set(:@logger, org_logger)
end
end

after(:all) do
FileUtils.rm_r('/tmp/one_gadget')
end

it 'cache_file' do
skip 'Windows so hard' unless RUBY_PLATFORM =~ /linux/
@hook_cache_file.call do |path|
expect(described_class.send(:cache_file)).to eq path
File.chmod(0o000, File.dirname(path))
expect(described_class.send(:cache_file)).to be nil
File.chmod(0o700, File.dirname(path))
end
end

it 'need_check?' do
@hook_cache_file.call do |path|
expect(described_class.send(:need_check?)).to be false
now = Time.now
allow(Time).to receive(:now).and_return(now + 7 * 24 * 3600)
expect(described_class.send(:need_check?)).to be true
IO.binwrite(path, 'never')
expect(described_class.send(:need_check?)).to be false
end
end

it 'check!' do
OneGadget::Helper.color_off!
@hook_cache_file.call do |path|
allow(described_class).to receive(:need_check?).and_return(true)
expect { @hook_logger.call { described_class.check! } }.to output(<<-EOS).to_stdout
[OneGadget] Checking for new versions of OneGadget
To disable this functionality, do
$ echo never > #{path}

[OneGadget] You have the latest version of OneGadget (#{OneGadget::VERSION})!

EOS
stub_const('OneGadget::VERSION', '0.0.0')
expect { @hook_logger.call { described_class.check! } }.to output(include(<<-EOS)).to_stdout
$ gem update one_gadget
EOS
end
OneGadget::Helper.color_on!
end
end