diff --git a/.travis.yml b/.travis.yml index c506e59..53f3295 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,22 +1,21 @@ language: ruby rvm: -- 2.2.0 - 2.3.0 - 2.4.0 - 2.5.0 - 2.6.0 env: global: - secure: A03DrflHssgYH/ekZlQUbp93B2aaFszXiiSQDxv1mm9oabuQuAQn+aGZmp1v1eA8SdSVu2PAeWNAUXFTAkgIbxRFUScsdbMyG2hdDiAie9t581PRdcRgcPWDPAoigj1xTgI9dbBTljlIJXQZ6+DuI3SpajfV8rksxRjqlgE5aec= - secure: fcBXclhQt2XL2iXQC6b3WVa6KGiWqboZK6AWFq2u1o53WK3Wz7eeG2OJwYakJvr23h4U2vvsTbMRT8fen6HXnywOHqPm83qQ6YdukoO5ky95s0zNFtVNn8Nj+ulZveb+zb+DlzXwuOUTSaBfgY0bN3XR12lM9b8qLy5UlZNGlNI= notifications: irc: channels: - "chat.freenode.net#kde-neon" on_success: change before_install: - sudo apt-get -qq update # Runtime deps asserted - sudo apt-get install -y gnupg2 gettext - gem update --system - gem update bundler diff --git a/lib/releaseme/requirement_checker.rb b/lib/releaseme/requirement_checker.rb index 5848842..5077c5f 100644 --- a/lib/releaseme/requirement_checker.rb +++ b/lib/releaseme/requirement_checker.rb @@ -1,163 +1,163 @@ #-- # Copyright (C) 2015-2017 Harald Sitter # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License as # published by the Free Software Foundation; either version 2 of # the License or (at your option) version 3 or any later version # accepted by the membership of KDE e.V. (or its successor approved # by the membership of KDE e.V.), which shall act as a proxy # defined in Section 14 of version 3 of the license. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . #++ # NB: cannot use other files as everything else is meant to load this first. require_relative 'silencer' module ReleaseMe # Makes sure the runtime requirements of releasme are met. class RequirementChecker # Finds executables. MakeMakefile is the only core ruby entity providing # PATH based executable lookup, unfortunately it is really not meant to be # used outside extconf.rb use cases as it mangles the main name scope by # injecting itself into it (which breaks for example the ffi gem). # The Shell interface's command-processor also has lookup code but it's not # Windows compatible. class Executable attr_reader :bin def initialize(bin) @bin = bin end # Finds the executable in PATH by joining it with all parts of PATH and # checking if the resulting absolute path exists and is an executable. # This also honor's Windows' PATHEXT to determine the list of potential # file extensions. So find('gpg2') will find gpg2 on POSIX and gpg2.exe # on Windows. def find # PATHEXT on Windows defines the valid executable extensions. exts = ENV.fetch('PATHEXT', '').split(';') # On other systems we'll work with no extensions. exts << '' if exts.empty? ENV['PATH'].split(File::PATH_SEPARATOR).each do |path| path = unescape_path(path) exts.each do |ext| file = File.join(path, bin + ext) return file if executable?(file) end end nil end private class << self def windows? @windows ||= ENV['RELEASEME_FORCE_WINDOWS'] || mswin? || mingw? end private def mswin? @mswin ||= /mswin/ =~ RUBY_PLATFORM end def mingw? @mingw ||= /mingw/ =~ RUBY_PLATFORM end end def windows? self.class.windows? end def executable?(path) stat = File.stat(path) rescue SystemCallError else return true if stat.file? && stat.executable? end def unescape_path(path) # Strip qutation. # NB: POSIX does not define any quoting mechanism so you simply cannot # have colons in PATH on POSIX systems as a side effect we mustn't # strip quotes as they have no syntactic meaning and instead are # assumed to be part of the path # http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap08.html#tag_08_03 return path.sub(/\A"(.*)"\z/m, '\1') if windows? path end end # NOTE: The versions are restricted upwards because behavior changes in the # language can result in unexpected outcome when using releaseme. i.e. # you may end up with a broken or malformed tar. To prevent this, a change # here must be followed by running `rake test` to pass the entire test suite # Also see the section on bumping versions in the REAMDE. - COMPATIBLE_RUBIES = %w[2.2.0 2.3.0 2.4.0 2.5.0 2.6.0].freeze + COMPATIBLE_RUBIES = %w[2.3.0 2.4.0 2.5.0 2.6.0].freeze REQUIRED_BINARIES = %w[svn git tar xz msgfmt gpg2].freeze def initialize @ruby_version = RUBY_VERSION end def check raise 'Not all requirements met.' unless check_ruby && check_binaries end private def check_ruby return true if ruby_compatible? print "- Ruby #{COMPATIBLE_RUBIES.join(' or ')} required." print " Currently using: #{@ruby_version}" false end def check_binaries missing_binaries.each do |m| print "- Missing binary: #{m}." end.empty? end def print(*args) return if Silencer.shutup? puts(*args) end def ruby_compatible? COMPATIBLE_RUBIES.each do |v| return true if compatible?(v) end false end def missing_binaries missing_binaries = [] REQUIRED_BINARIES.each do |r| missing_binaries << missing?(r) end missing_binaries.compact end def compatible?(a) Gem::Dependency.new('', "~> #{a}").match?('', @ruby_version) end def missing?(bin) return bin unless Executable.new(bin).find nil end end end diff --git a/test/requirement_checker_test.rb b/test/requirement_checker_test.rb index 4dae623..0ae410e 100644 --- a/test/requirement_checker_test.rb +++ b/test/requirement_checker_test.rb @@ -1,117 +1,117 @@ require 'fileutils' require_relative 'lib/testme' require_relative '../lib/releaseme/requirement_checker' class TestRequirementChecker < Testme class ExecutableTest < Testme Executable = ReleaseMe::RequirementChecker::Executable def setup ENV['PATH'] = Dir.pwd end def make_exe(name) File.write(name, '') File.chmod(0o700, name) end def test_exec_not_windows # If env looks windowsy, skip this test. It won't pass because we look # for gpg2.exe which obviously won't exist. return if ENV['PATHEXT'] make_exe('gpg2') assert_equal "#{Dir.pwd}/gpg2", Executable.new('gpg2').find assert_nil Executable.new('foobar').find end def test_windows # windows ENV['RELEASEME_FORCE_WINDOWS'] make_exe('gpg2.exe') make_exe('svn.com') ENV['PATHEXT'] = '.COM;.EXE'.downcase # downcase so this passes on Linux ENV['PATH'] = Dir.pwd assert_equal "#{Dir.pwd}/gpg2.exe", Executable.new('gpg2').find assert_equal "#{Dir.pwd}/svn.com", Executable.new('svn').find assert_nil Executable.new('foobar').find end end def assert_ruby_version_compatible(version) checker = ReleaseMe::RequirementChecker.new checker.instance_variable_set(:@ruby_version, version) assert(checker.send(:ruby_compatible?), "Ruby version #{version} NOT compatible but should be") end def assert_ruby_version_not_compatible(version) checker = ReleaseMe::RequirementChecker.new checker.instance_variable_set(:@ruby_version, version) assert(!checker.send(:ruby_compatible?), "Ruby version #{version} compatible but should not be") assert_raises { checker.check } end def with_path(path) orig_path = ENV.fetch('PATH') ENV['PATH'] = path yield ensure ENV['PATH'] = orig_path if orig_path end def test_versions compatibles = %w[ - 2.2 - 2.2.0 - 2.2.1 2.3 2.3.1 2.4 2.4.1 2.5 2.5.1 2.6 2.6.0 ] compatibles.each { |i| assert_ruby_version_compatible(i) } incompatibles = %w[ 1.9.0 2.0 2.0.99 + 2.2 + 2.2.0 + 2.2.1 2.7 2.7.1 ] incompatibles.each { |i| assert_ruby_version_not_compatible(i) } end def all_binaries ReleaseMe::RequirementChecker.const_get(:REQUIRED_BINARIES) end def test_missing_binaries with_path('') do checker = ReleaseMe::RequirementChecker.new missing_binaries = checker.send(:missing_binaries) expected_missing_binaries = all_binaries assert_equal(expected_missing_binaries, missing_binaries) assert_raises { checker.check } end end def test_existing_binaries exec_names = all_binaries if ReleaseMe::RequirementChecker::Executable.windows? exec_names = all_binaries.collect { |x| "#{x}.exe" } end FileUtils.touch(exec_names) FileUtils.chmod('+x', exec_names) with_path(Dir.pwd) do missing_binaries = ReleaseMe::RequirementChecker.new.send(:missing_binaries) assert_equal([], missing_binaries) end end end