2018-12-23 12:14:25 +05:30
|
|
|
# frozen_string_literal: true
|
|
|
|
|
2017-08-17 22:00:37 +05:30
|
|
|
module Gitlab
|
|
|
|
module Git
|
|
|
|
# Class for parsing Git attribute files and extracting the attributes for
|
|
|
|
# file patterns.
|
2018-03-17 18:26:18 +05:30
|
|
|
class AttributesParser
|
2018-10-15 14:42:47 +05:30
|
|
|
def initialize(attributes_data = "")
|
2018-03-17 18:26:18 +05:30
|
|
|
@data = attributes_data || ""
|
2017-08-17 22:00:37 +05:30
|
|
|
end
|
|
|
|
|
|
|
|
# Returns all the Git attributes for the given path.
|
|
|
|
#
|
2018-03-17 18:26:18 +05:30
|
|
|
# file_path - A path to a file for which to get the attributes.
|
2017-08-17 22:00:37 +05:30
|
|
|
#
|
|
|
|
# Returns a Hash.
|
2018-03-17 18:26:18 +05:30
|
|
|
def attributes(file_path)
|
|
|
|
absolute_path = File.join('/', file_path)
|
2017-08-17 22:00:37 +05:30
|
|
|
|
|
|
|
patterns.each do |pattern, attrs|
|
2018-03-17 18:26:18 +05:30
|
|
|
return attrs if File.fnmatch?(pattern, absolute_path)
|
2017-08-17 22:00:37 +05:30
|
|
|
end
|
|
|
|
|
|
|
|
{}
|
|
|
|
end
|
|
|
|
|
|
|
|
# Returns a Hash containing the file patterns and their attributes.
|
|
|
|
def patterns
|
2018-10-15 14:42:47 +05:30
|
|
|
@patterns ||= parse_data
|
2017-08-17 22:00:37 +05:30
|
|
|
end
|
|
|
|
|
|
|
|
# Parses an attribute string.
|
|
|
|
#
|
|
|
|
# These strings can be in the following formats:
|
|
|
|
#
|
|
|
|
# text # => { "text" => true }
|
|
|
|
# -text # => { "text" => false }
|
|
|
|
# key=value # => { "key" => "value" }
|
|
|
|
#
|
|
|
|
# string - The string to parse.
|
|
|
|
#
|
|
|
|
# Returns a Hash containing the attributes and their values.
|
|
|
|
def parse_attributes(string)
|
|
|
|
values = {}
|
|
|
|
dash = '-'
|
|
|
|
equal = '='
|
|
|
|
binary = 'binary'
|
|
|
|
|
|
|
|
string.split(/\s+/).each do |chunk|
|
|
|
|
# Data such as "foo = bar" should be treated as "foo" and "bar" being
|
|
|
|
# separate boolean attributes.
|
|
|
|
next if chunk == equal
|
|
|
|
|
|
|
|
key = chunk
|
|
|
|
|
|
|
|
# Input: "-foo"
|
|
|
|
if chunk.start_with?(dash)
|
|
|
|
key = chunk.byteslice(1, chunk.length - 1)
|
|
|
|
value = false
|
|
|
|
|
|
|
|
# Input: "foo=bar"
|
|
|
|
elsif chunk.include?(equal)
|
|
|
|
key, value = chunk.split(equal, 2)
|
|
|
|
|
|
|
|
# Input: "foo"
|
|
|
|
else
|
|
|
|
value = true
|
|
|
|
end
|
|
|
|
|
|
|
|
values[key] = value
|
|
|
|
|
|
|
|
# When the "binary" option is set the "diff" option should be set to
|
|
|
|
# the inverse. If "diff" is later set it should overwrite the
|
|
|
|
# automatically set value.
|
|
|
|
values['diff'] = false if key == binary && value
|
|
|
|
end
|
|
|
|
|
|
|
|
values
|
|
|
|
end
|
|
|
|
|
|
|
|
# Iterates over every line in the attributes file.
|
|
|
|
def each_line
|
2018-03-17 18:26:18 +05:30
|
|
|
@data.each_line do |line|
|
|
|
|
break unless line.valid_encoding?
|
2017-08-17 22:00:37 +05:30
|
|
|
|
2018-03-17 18:26:18 +05:30
|
|
|
yield line.strip
|
2017-08-17 22:00:37 +05:30
|
|
|
end
|
2020-05-24 23:13:21 +05:30
|
|
|
# Catch invalid byte sequences
|
|
|
|
rescue ArgumentError
|
2017-08-17 22:00:37 +05:30
|
|
|
end
|
|
|
|
|
|
|
|
private
|
|
|
|
|
2018-10-15 14:42:47 +05:30
|
|
|
# Parses the Git attributes file contents.
|
|
|
|
def parse_data
|
2017-08-17 22:00:37 +05:30
|
|
|
pairs = []
|
|
|
|
comment = '#'
|
|
|
|
|
|
|
|
each_line do |line|
|
|
|
|
next if line.start_with?(comment) || line.empty?
|
|
|
|
|
|
|
|
pattern, attrs = line.split(/\s+/, 2)
|
|
|
|
|
|
|
|
parsed = attrs ? parse_attributes(attrs) : {}
|
|
|
|
|
2018-03-17 18:26:18 +05:30
|
|
|
absolute_pattern = File.join('/', pattern)
|
|
|
|
pairs << [absolute_pattern, parsed]
|
2017-08-17 22:00:37 +05:30
|
|
|
end
|
|
|
|
|
|
|
|
# Newer entries take precedence over older entries.
|
|
|
|
pairs.reverse.to_h
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|