gitlab-org--gitlab-foss/lib/gitlab/git/gitmodules_parser.rb
David Turner b30c16aa32 repository: index submodules by path
Submodules have a name in the configuration, but this name is simply
the path at which the submodule was initially checked in (by default
-- the name is totally arbitrary).  If a submodule is moved, it
retains its original name, but its path changes.  Since we discover
submodules inside trees, we have their path but not necessarily their
name.

Make the submodules() function return the submodule hash indexed by
path rather than name, so that renamed submodules can be looked up.

Signed-off-by: David Turner <novalis@novalis.org>
2017-06-16 14:37:13 -04:00

77 lines
2 KiB
Ruby

module Gitlab
module Git
class GitmodulesParser
def initialize(content)
@content = content
end
# Parses the contents of a .gitmodules file and returns a hash of
# submodule information, indexed by path.
def parse
reindex_by_path(get_submodules_by_name)
end
private
class State
def initialize
@result = {}
@current_submodule = nil
end
def start_section(section)
# In some .gitmodules files (e.g. nodegit's), a header
# with the same name appears multiple times; we want to
# accumulate the configs across these
@current_submodule = @result[section] || { 'name' => section }
@result[section] = @current_submodule
end
def set_attribute(attr, value)
@current_submodule[attr] = value
end
def section_started?
!@current_submodule.nil?
end
def submodules_by_name
@result
end
end
def get_submodules_by_name
iterator = State.new
@content.split("\n").each_with_object(iterator) do |text, iterator|
next if text =~ /^\s*#/
if text =~ /\A\[submodule "(?<name>[^"]+)"\]\z/
iterator.start_section($~[:name])
else
next unless iterator.section_started?
next unless text =~ /\A\s*(?<key>\w+)\s*=\s*(?<value>.*)\z/
value = $~[:value].chomp
iterator.set_attribute($~[:key], value)
end
end
iterator.submodules_by_name
end
def reindex_by_path(submodules_by_name)
# Convert from an indexed by name to an array indexed by path
# If a submodule doesn't have a path, it is considered bogus
# and is ignored
submodules_by_name.each_with_object({}) do |(name, data), results|
path = data.delete 'path'
next unless path
results[path] = data
end
end
end
end
end