class Dependabot::Gradle::FileParser
Constants
- DEPENDENCY_DECLARATION_REGEX
- DEPENDENCY_SET_DECLARATION_REGEX
- DEPENDENCY_SET_ENTRY_REGEX
- PART
- PLUGIN_BLOCK_DECLARATION_REGEX
- PLUGIN_ID_REGEX
- PROPERTY_REGEX
- SUPPORTED_BUILD_FILE_NAMES
- VSN_PART
Public Instance Methods
parse()
click to toggle source
# File lib/dependabot/gradle/file_parser.rb, line 41 def parse dependency_set = DependencySet.new buildfiles.each do |buildfile| dependency_set += buildfile_dependencies(buildfile) end script_plugin_files.each do |plugin_file| dependency_set += buildfile_dependencies(plugin_file) end dependency_set.dependencies end
Private Instance Methods
argument_from_string(string, arg_name)
click to toggle source
# File lib/dependabot/gradle/file_parser.rb, line 170 def argument_from_string(string, arg_name) string. match(map_value_regex(arg_name))&. named_captures&. fetch("value") end
buildfile_dependencies(buildfile)
click to toggle source
# File lib/dependabot/gradle/file_parser.rb, line 58 def buildfile_dependencies(buildfile) dependency_set = DependencySet.new dependency_set += shortform_buildfile_dependencies(buildfile) dependency_set += keyword_arg_buildfile_dependencies(buildfile) dependency_set += dependency_set_dependencies(buildfile) dependency_set += plugin_dependencies(buildfile) dependency_set end
buildfiles()
click to toggle source
# File lib/dependabot/gradle/file_parser.rb, line 295 def buildfiles @buildfiles ||= dependency_files.select do |f| f.name.end_with?(*SUPPORTED_BUILD_FILE_NAMES) end end
check_required_files()
click to toggle source
# File lib/dependabot/gradle/file_parser.rb, line 312 def check_required_files raise "No build.gradle or build.gradle.kts!" unless original_file end
closing_bracket_index(string)
click to toggle source
# File lib/dependabot/gradle/file_parser.rb, line 283 def closing_bracket_index(string) closes_required = 1 string.chars.each_with_index do |char, index| closes_required += 1 if char == "{" closes_required -= 1 if char == "}" return index if closes_required.zero? end 0 end
dependency_from(details_hash:, buildfile:, in_dependency_set: false)
click to toggle source
# File lib/dependabot/gradle/file_parser.rb, line 177 def dependency_from(details_hash:, buildfile:, in_dependency_set: false) group = evaluated_value(details_hash[:group], buildfile) name = evaluated_value(details_hash[:name], buildfile) version = evaluated_value(details_hash[:version], buildfile) extra_groups = details_hash[:extra_groups] || [] dependency_name = if group == "plugins" then name else "#{group}:#{name}" end groups = if group == "plugins" then ["plugins"] + extra_groups else [] end source = source_from(group, name, version) # If we can't evaluate a property they we won't be able to # update this dependency return if "#{dependency_name}:#{version}".match?(PROPERTY_REGEX) return unless Gradle::Version.correct?(version) Dependency.new( name: dependency_name, version: version, requirements: [{ requirement: version, file: buildfile.name, source: source, groups: groups, metadata: dependency_metadata(details_hash, in_dependency_set) }], package_manager: "gradle" ) end
dependency_metadata(details_hash, in_dependency_set)
click to toggle source
# File lib/dependabot/gradle/file_parser.rb, line 226 def dependency_metadata(details_hash, in_dependency_set) version_property_name = details_hash[:version]. match(PROPERTY_REGEX)&. named_captures&.fetch("property_name") return unless version_property_name || in_dependency_set metadata = {} metadata[:property_name] = version_property_name if version_property_name if in_dependency_set metadata[:dependency_set] = { group: details_hash[:group], version: details_hash[:version] } end metadata end
dependency_set_dependencies(buildfile)
click to toggle source
# File lib/dependabot/gradle/file_parser.rb, line 104 def dependency_set_dependencies(buildfile) dependency_set = DependencySet.new dependency_set_blocks = [] prepared_content(buildfile).scan(DEPENDENCY_SET_DECLARATION_REGEX) do mch = Regexp.last_match dependency_set_blocks << { arguments: mch.named_captures.fetch("arguments"), block: mch.post_match[0..closing_bracket_index(mch.post_match)] } end dependency_set_blocks.each do |blk| group = argument_from_string(blk[:arguments], "group") version = argument_from_string(blk[:arguments], "version") next unless group && version blk[:block].scan(DEPENDENCY_SET_ENTRY_REGEX).flatten.each do |name| dep = dependency_from( details_hash: { group: group, name: name, version: version }, buildfile: buildfile, in_dependency_set: true ) dependency_set << dep if dep end end dependency_set end
evaluated_value(value, buildfile)
click to toggle source
# File lib/dependabot/gradle/file_parser.rb, line 245 def evaluated_value(value, buildfile) return value unless value.scan(PROPERTY_REGEX).count == 1 property_name = value.match(PROPERTY_REGEX). named_captures.fetch("property_name") property_value = property_value_finder.property_value( property_name: property_name, callsite_buildfile: buildfile ) return value unless property_value value.gsub(PROPERTY_REGEX, property_value) end
extra_groups(line)
click to toggle source
# File lib/dependabot/gradle/file_parser.rb, line 166 def extra_groups(line) line.match(/kotlin(\s+#{PLUGIN_ID_REGEX}|\(#{PLUGIN_ID_REGEX}\))/) ? ["kotlin"] : [] end
keyword_arg_buildfile_dependencies(buildfile)
click to toggle source
# File lib/dependabot/gradle/file_parser.rb, line 86 def keyword_arg_buildfile_dependencies(buildfile) dependency_set = DependencySet.new prepared_content(buildfile).lines.each do |line| name = argument_from_string(line, "name") group = argument_from_string(line, "group") version = argument_from_string(line, "version") next unless name && group && version details = { name: name, group: group, version: version } dep = dependency_from(details_hash: details, buildfile: buildfile) dependency_set << dep if dep end dependency_set end
map_value_regex(key)
click to toggle source
# File lib/dependabot/gradle/file_parser.rb, line 54 def map_value_regex(key) /(?:^|\s|,|\()#{Regexp.quote(key)}(\s*=|:)\s*['"](?<value>[^'"]+)['"]/ end
original_file()
click to toggle source
# File lib/dependabot/gradle/file_parser.rb, line 316 def original_file dependency_files.find do |f| SUPPORTED_BUILD_FILE_NAMES.include?(f.name) end end
plugin_dependencies(buildfile)
click to toggle source
# File lib/dependabot/gradle/file_parser.rb, line 137 def plugin_dependencies(buildfile) dependency_set = DependencySet.new plugin_blocks = [] prepared_content(buildfile).scan(PLUGIN_BLOCK_DECLARATION_REGEX) do mch = Regexp.last_match plugin_blocks << mch.post_match[0..closing_bracket_index(mch.post_match)] end plugin_blocks.each do |blk| blk.lines.each do |line| name_regex = /(id|kotlin)(\s+#{PLUGIN_ID_REGEX}|\(#{PLUGIN_ID_REGEX}\))/ name = line.match(name_regex)&.named_captures&.fetch("id") version_regex = /version\s+['"](?<version>#{VSN_PART})['"]/ version = line.match(version_regex)&.named_captures&. fetch("version") next unless name && version details = { name: name, group: "plugins", extra_groups: extra_groups(line), version: version } dep = dependency_from(details_hash: details, buildfile: buildfile) dependency_set << dep if dep end end dependency_set end
prepared_content(buildfile)
click to toggle source
# File lib/dependabot/gradle/file_parser.rb, line 265 def prepared_content(buildfile) # Remove any comments prepared_content = buildfile.content. gsub(%r{(?<=^|\s)//.*$}, "\n"). gsub(%r{(?<=^|\s)/\*.*?\*/}m, "") # Remove the dependencyVerification section added by Gradle Witness # (TODO: Support updating this in the FileUpdater) prepared_content.dup.scan(/dependencyVerification\s*{/) do mtch = Regexp.last_match block = mtch.post_match[0..closing_bracket_index(mtch.post_match)] prepared_content.gsub!(block, "") end prepared_content end
property_value_finder()
click to toggle source
# File lib/dependabot/gradle/file_parser.rb, line 260 def property_value_finder @property_value_finder ||= PropertyValueFinder.new(dependency_files: dependency_files) end
script_plugin_files()
click to toggle source
# File lib/dependabot/gradle/file_parser.rb, line 301 def script_plugin_files @script_plugin_files ||= buildfiles.flat_map do |buildfile| buildfile.content. scan(/apply from(\s+=|:)\s+['"]([^'"]+)['"]/).flatten. map { |f| dependency_files.find { |bf| bf.name == f } }. compact end. uniq end
shortform_buildfile_dependencies(buildfile)
click to toggle source
# File lib/dependabot/gradle/file_parser.rb, line 69 def shortform_buildfile_dependencies(buildfile) dependency_set = DependencySet.new prepared_content(buildfile).scan(DEPENDENCY_DECLARATION_REGEX) do declaration = Regexp.last_match.named_captures.fetch("declaration") group, name, version = declaration.split(":") version, _packaging_type = version.split("@") details = { group: group, name: name, version: version } dep = dependency_from(details_hash: details, buildfile: buildfile) dependency_set << dep if dep end dependency_set end
source_from(group, name, version)
click to toggle source
# File lib/dependabot/gradle/file_parser.rb, line 213 def source_from(group, name, version) return nil unless group&.start_with?("com.github") && version.match?(/\A[0-9a-f]{40}\Z/) account = group.sub("com.github.", "") { type: "git", url: "https://github.com/#{account}/#{name}", branch: nil, ref: version } end