diff --git a/lib/license_finder/package_managers/conan.rb b/lib/license_finder/package_managers/conan.rb index 0ec7f7e3..fe77c4b7 100644 --- a/lib/license_finder/package_managers/conan.rb +++ b/lib/license_finder/package_managers/conan.rb @@ -1,27 +1,69 @@ # frozen_string_literal: true require 'license_finder/package_utils/conan_info_parser' +require 'license_finder/package_utils/conan_info_parser_v2' module LicenseFinder class Conan < PackageManager def possible_package_paths - [project_path.join('conanfile.txt')] + [project_path.join('conanfile.txt'), project_path.join('conanfile.py')] end - def current_packages - install_command = 'conan install .' + def license_file_is_good?(license_file_path) + !license_file_path.nil? && File.file?(license_file_path) + end + + def license_file(project_path, name) + candidates = Dir.glob("#{project_path}/licenses/#{name}/**/LICENSE*") + candidates.each do |candidate| + return candidate if license_file_is_good?(candidate) + end + nil + end + + def deps_list_conan_v1(project_path) info_command = 'conan info .' - Dir.chdir(project_path) { Cmd.run(install_command) } info_output, _stderr, _status = Dir.chdir(project_path) { Cmd.run(info_command) } + return nil if info_output.empty? info_parser = ConanInfoParser.new + info_parser.parse(info_output) + end + + def deps_list_conan_v2(project_path) + info_command = 'conan graph info .' + info_output, stderr, _status = Dir.chdir(project_path) { Cmd.run(info_command) } + if info_output.empty? + return if stderr.empty? + + info_output = stderr + end + info_parser = ConanInfoParserV2.new + info_parser.parse(info_output) + end + + def deps_list(project_path) + deps = deps_list_conan_v1(project_path) + deps = deps_list_conan_v2(project_path) if deps.nil? || deps.empty? + deps + end + + def current_packages + install_command = 'conan install .' + Dir.chdir(project_path) { Cmd.run(install_command) } + + deps = deps_list(project_path) + return [] if deps.nil? - deps = info_parser.parse(info_output) deps.map do |dep| name, version = dep['name'].split('/') - url = dep['URL'] - license_file_path = Dir.glob("#{project_path}/licenses/#{name}/**/LICENSE*").first - ConanPackage.new(name, version, File.open(license_file_path).read, url) unless name == 'conanfile.txt' + license_file_path = license_file(project_path, name) + + next unless license_file_is_good?(license_file_path) + + url = dep['homepage'] + url = dep['url'] if url.nil? + ConanPackage.new(name, version, File.open(license_file_path).read, url) end.compact end end diff --git a/lib/license_finder/package_utils/conan_info_parser.rb b/lib/license_finder/package_utils/conan_info_parser.rb index 2d6eecd8..9d72561f 100644 --- a/lib/license_finder/package_utils/conan_info_parser.rb +++ b/lib/license_finder/package_utils/conan_info_parser.rb @@ -31,9 +31,9 @@ def parse(info) def parse_key_val(line) key, val = key_val(line) if val - @current_project[key] = val + @current_project[key.downcase] = val elsif line.start_with?(' ') - @current_key = key + @current_key = key.downcase @current_vals = [] @state = :val_list else diff --git a/lib/license_finder/package_utils/conan_info_parser_v2.rb b/lib/license_finder/package_utils/conan_info_parser_v2.rb new file mode 100644 index 00000000..fa1d2965 --- /dev/null +++ b/lib/license_finder/package_utils/conan_info_parser_v2.rb @@ -0,0 +1,82 @@ +# frozen_string_literal: true + +module LicenseFinder + class ConanInfoParserV2 + def parse(info) + @lines = info.lines.map(&:chomp) + @state = :project_level # state of the state machine + @projects = [] # list of projects + @current_project = nil # current project being populated in the SM + @current_vals = [] # current val list being populate in the SM + @current_key = nil # current key to be associated with the current val + + line = @lines.shift + line = @lines.shift while line != '======== Basic graph information ========' + + while (line = @lines.shift) + next if line == '' + + case @state + when :project_level + @current_project = {} + name, _id = line.strip.split('#') + @current_project['name'] = name + @state = :key_val + when :key_val + parse_key_val(line) + when :val_list + parse_val_list(line) + end + end + wrap_up + end + + private + + def parse_key_val(line) + key, val = key_val(line) + if val + @current_project[key.downcase] = val + elsif line.start_with?(' ') + @current_key = key.downcase + @current_vals = [] + @state = :val_list + else + change_to_new_project_state line + end + end + + def parse_val_list(line) + if val_list_level(line) + @current_vals << line.strip + else + @current_project[@current_key] = @current_vals + if line.start_with?(' ') + @state = :key_val + @lines.unshift(line) + else + change_to_new_project_state line + end + end + end + + def wrap_up + @current_project[@current_key] = @current_vals if @current_vals.count && @current_key + @projects << @current_project + end + + def val_list_level(line) + line.start_with?(' ') + end + + def change_to_new_project_state(line) + @state = :project_level + @projects << @current_project + @lines.unshift(line) + end + + def key_val(info) + info.split(':', 2).map(&:strip!) + end + end +end diff --git a/spec/lib/license_finder/package_managers/conan_info_parser_spec.rb b/spec/lib/license_finder/package_managers/conan_info_parser_spec.rb index 79fef902..b18376ee 100644 --- a/spec/lib/license_finder/package_managers/conan_info_parser_spec.rb +++ b/spec/lib/license_finder/package_managers/conan_info_parser_spec.rb @@ -9,55 +9,55 @@ module LicenseFinder [ { 'name' => 'conanfile.txt', - 'ID' => '4c3dfe99a9c2d5003148e0054b9bacf58ac69f66', - 'BuildID' => 'None', - 'Requires' => ['Poco/1.7.9@pocoproject/stable', 'OpenSSL/1.0.2l@conan/stable', 'range-v3/0.3.0@ericniebler/stable'] + 'id' => '4c3dfe99a9c2d5003148e0054b9bacf58ac69f66', + 'buildid' => 'None', + 'requires' => ['Poco/1.7.9@pocoproject/stable', 'OpenSSL/1.0.2l@conan/stable', 'range-v3/0.3.0@ericniebler/stable'] }, { 'name' => 'OpenSSL/1.0.2l@conan/stable', - 'ID' => '0197c20e330042c026560da838f5b4c4bf094b8a', - 'BuildID' => 'None', - 'Remote' => 'conan-center=https://center.conan.io', - 'URL' => 'http://github.com/lasote/conan-openssl', - 'License' => 'The current OpenSSL licence is an \'Apache style\' license: https://www.openssl.org/source/license.html', - 'Updates' => 'Version not checked', - 'Creation date' => '2017-08-21 10:28:57', - 'Required by' => ['Poco/1.7.9@pocoproject/stable', 'conanfile.txt'], - 'Requires' => ['zlib/1.2.11@conan/stable'] + 'id' => '0197c20e330042c026560da838f5b4c4bf094b8a', + 'buildid' => 'None', + 'remote' => 'conan-center=https://center.conan.io', + 'url' => 'http://github.com/lasote/conan-openssl', + 'license' => 'The current OpenSSL licence is an \'Apache style\' license: https://www.openssl.org/source/license.html', + 'updates' => 'Version not checked', + 'creation date' => '2017-08-21 10:28:57', + 'required by' => ['Poco/1.7.9@pocoproject/stable', 'conanfile.txt'], + 'requires' => ['zlib/1.2.11@conan/stable'] }, { 'name' => 'Poco/1.7.9@pocoproject/stable', - 'ID' => '33fe7ea34efc04fb6d81fabd9e34f51da57f9e09', - 'BuildID' => 'None', - 'Remote' => 'conan-center=https://center.conan.io', - 'URL' => 'http://github.com/lasote/conan-poco', - 'License' => 'The Boost Software License 1.0', - 'Updates' => 'Version not checked', - 'Creation date' => '2017-09-20 16:51:10', - 'Required by' => ['conanfile.txt'], - 'Requires' => ['OpenSSL/1.0.2l@conan/stable'] + 'id' => '33fe7ea34efc04fb6d81fabd9e34f51da57f9e09', + 'buildid' => 'None', + 'remote' => 'conan-center=https://center.conan.io', + 'url' => 'http://github.com/lasote/conan-poco', + 'license' => 'The Boost Software License 1.0', + 'updates' => 'Version not checked', + 'creation date' => '2017-09-20 16:51:10', + 'required by' => ['conanfile.txt'], + 'requires' => ['OpenSSL/1.0.2l@conan/stable'] }, { 'name' => 'range-v3/0.3.0@ericniebler/stable', - 'ID' => '5ab84d6acfe1f23c4fae0ab88f26e3a396351ac9', - 'BuildID' => 'None', - 'Remote' => 'conan-center=https://center.conan.io', - 'URL' => 'https://github.com/ericniebler/range-v3', - 'License' => 'Boost Software License - Version 1.0 - August 17th, 2003', - 'Updates' => 'Version not checked', - 'Creation date' => '2017-06-30 13:20:56', - 'Required by' => ['conanfile.txt'] + 'id' => '5ab84d6acfe1f23c4fae0ab88f26e3a396351ac9', + 'buildid' => 'None', + 'remote' => 'conan-center=https://center.conan.io', + 'url' => 'https://github.com/ericniebler/range-v3', + 'license' => 'Boost Software License - Version 1.0 - August 17th, 2003', + 'updates' => 'Version not checked', + 'creation date' => '2017-06-30 13:20:56', + 'required by' => ['conanfile.txt'] }, { 'name' => 'zlib/1.2.11@conan/stable', - 'ID' => '09512ff863f37e98ed748eadd9c6df3e4ea424a8', - 'BuildID' => 'None', - 'Remote' => 'conan-center=https://center.conan.io', - 'URL' => 'http://github.com/lasote/conan-zlib', - 'License' => 'http://www.zlib.net/zlib_license.html', - 'Updates' => 'Version not checked', - 'Creation date' => '2017-09-25 14:42:53', - 'Required by' => ['OpenSSL/1.0.2l@conan/stable'] + 'id' => '09512ff863f37e98ed748eadd9c6df3e4ea424a8', + 'buildid' => 'None', + 'remote' => 'conan-center=https://center.conan.io', + 'url' => 'http://github.com/lasote/conan-zlib', + 'license' => 'http://www.zlib.net/zlib_license.html', + 'updates' => 'Version not checked', + 'creation date' => '2017-09-25 14:42:53', + 'required by' => ['OpenSSL/1.0.2l@conan/stable'] } ] end