Commit 2a39280d authored by Rémy Coutable's avatar Rémy Coutable

Merge branch 'moved-submodules' into 'master'

repository: index submodules by path

See merge request !10798
parents 8a3f886b b30c16aa
---
title: 'Handle renamed submodules in repository browser'
merge_request: 10798
author: David Turner
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
...@@ -617,9 +617,9 @@ module Gitlab ...@@ -617,9 +617,9 @@ module Gitlab
# #
# Ex. # Ex.
# { # {
# "rack" => { # "current_path/rack" => {
# "name" => "original_path/rack",
# "id" => "c67be4624545b4263184c4a0e8f887efd0a66320", # "id" => "c67be4624545b4263184c4a0e8f887efd0a66320",
# "path" => "rack",
# "url" => "git://github.com/chneukirchen/rack.git" # "url" => "git://github.com/chneukirchen/rack.git"
# }, # },
# "encoding" => { # "encoding" => {
...@@ -637,7 +637,8 @@ module Gitlab ...@@ -637,7 +637,8 @@ module Gitlab
return {} return {}
end end
parse_gitmodules(commit, content) parser = GitmodulesParser.new(content)
fill_submodule_ids(commit, parser.parse)
end end
# Return total commits count accessible from passed ref # Return total commits count accessible from passed ref
...@@ -998,42 +999,19 @@ module Gitlab ...@@ -998,42 +999,19 @@ module Gitlab
end end
end end
# Parses the contents of a .gitmodules file and returns a hash of # Fill in the 'id' field of a submodule hash from its values
# submodule information. # as-of +commit+. Return a Hash consisting only of entries
def parse_gitmodules(commit, content) # from the submodule hash for which the 'id' field is filled.
modules = {} def fill_submodule_ids(commit, submodule_data)
submodule_data.each do |path, data|
name = nil id = begin
content.each_line do |line| blob_content(commit, path)
case line.strip rescue InvalidBlobName
when /\A\[submodule "(?<name>[^"]+)"\]\z/ # Submodule header nil
name = $~[:name]
modules[name] = {}
when /\A(?<key>\w+)\s*=\s*(?<value>.*)\z/ # Key/value pair
key = $~[:key]
value = $~[:value].chomp
next unless name && modules[name]
modules[name][key] = value
if key == 'path'
begin
modules[name]['id'] = blob_content(commit, value)
rescue InvalidBlobName
# The current entry is invalid
modules.delete(name)
name = nil
end
end
when /\A#/ # Comment
next
else # Invalid line
name = nil
end end
data['id'] = id
end end
submodule_data.select { |path, data| data['id'] }
modules
end end
# Returns true if +commit+ introduced changes to +path+, using commit # Returns true if +commit+ introduced changes to +path+, using commit
......
require 'spec_helper'
describe Gitlab::Git::GitmodulesParser do
it 'should parse a .gitmodules file correctly' do
parser = described_class.new(<<-'GITMODULES'.strip_heredoc)
[submodule "vendor/libgit2"]
path = vendor/libgit2
[submodule "vendor/libgit2"]
url = https://github.com/nodegit/libgit2.git
# a comment
[submodule "moved"]
path = new/path
url = https://example.com/some/project
[submodule "bogus"]
url = https://example.com/another/project
GITMODULES
modules = parser.parse
expect(modules).to eq({
'vendor/libgit2' => { 'name' => 'vendor/libgit2',
'url' => 'https://github.com/nodegit/libgit2.git' },
'new/path' => { 'name' => 'moved',
'url' => 'https://example.com/some/project' }
})
end
end
...@@ -358,7 +358,7 @@ describe Gitlab::Git::Repository, seed_helper: true do ...@@ -358,7 +358,7 @@ describe Gitlab::Git::Repository, seed_helper: true do
expect(submodule).to eq([ expect(submodule).to eq([
"six", { "six", {
"id" => "409f37c4f05865e4fb208c771485f211a22c4c2d", "id" => "409f37c4f05865e4fb208c771485f211a22c4c2d",
"path" => "six", "name" => "six",
"url" => "git://github.com/randx/six.git" "url" => "git://github.com/randx/six.git"
} }
]) ])
...@@ -366,14 +366,14 @@ describe Gitlab::Git::Repository, seed_helper: true do ...@@ -366,14 +366,14 @@ describe Gitlab::Git::Repository, seed_helper: true do
it 'should handle nested submodules correctly' do it 'should handle nested submodules correctly' do
nested = submodules['nested/six'] nested = submodules['nested/six']
expect(nested['path']).to eq('nested/six') expect(nested['name']).to eq('nested/six')
expect(nested['url']).to eq('git://github.com/randx/six.git') expect(nested['url']).to eq('git://github.com/randx/six.git')
expect(nested['id']).to eq('24fb71c79fcabc63dfd8832b12ee3bf2bf06b196') expect(nested['id']).to eq('24fb71c79fcabc63dfd8832b12ee3bf2bf06b196')
end end
it 'should handle deeply nested submodules correctly' do it 'should handle deeply nested submodules correctly' do
nested = submodules['deeper/nested/six'] nested = submodules['deeper/nested/six']
expect(nested['path']).to eq('deeper/nested/six') expect(nested['name']).to eq('deeper/nested/six')
expect(nested['url']).to eq('git://github.com/randx/six.git') expect(nested['url']).to eq('git://github.com/randx/six.git')
expect(nested['id']).to eq('24fb71c79fcabc63dfd8832b12ee3bf2bf06b196') expect(nested['id']).to eq('24fb71c79fcabc63dfd8832b12ee3bf2bf06b196')
end end
...@@ -393,7 +393,7 @@ describe Gitlab::Git::Repository, seed_helper: true do ...@@ -393,7 +393,7 @@ describe Gitlab::Git::Repository, seed_helper: true do
expect(submodules.first).to eq([ expect(submodules.first).to eq([
"six", { "six", {
"id" => "409f37c4f05865e4fb208c771485f211a22c4c2d", "id" => "409f37c4f05865e4fb208c771485f211a22c4c2d",
"path" => "six", "name" => "six",
"url" => "git://github.com/randx/six.git" "url" => "git://github.com/randx/six.git"
} }
]) ])
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment