submodule_helper.rb 3.45 KB
Newer Older
1 2
# frozen_string_literal: true

3
module SubmoduleHelper
4
  extend self
5

6 7
  VALID_SUBMODULE_PROTOCOLS = %w[http https git ssh].freeze

8
  # links to files listing for submodule if submodule is a project on this server
9 10
  def submodule_links(submodule_item, ref = nil, repository = @repository)
    url = repository.submodule_url_for(ref, submodule_item.path)
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
11

12
    if url == '.' || url == './'
13
      url = File.join(Gitlab.config.gitlab.url, repository.project.full_path)
14 15
    end

16
    if url =~ %r{([^/:]+)/([^/]+(?:\.git)?)\Z}
17
      namespace, project = $1, $2
18 19 20 21 22 23 24 25 26 27
      gitlab_hosts = [Gitlab.config.gitlab.url,
                      Gitlab.config.gitlab_shell.ssh_path_prefix]

      gitlab_hosts.each do |host|
        if url.start_with?(host)
          namespace, _, project = url.sub(host, '').rpartition('/')
          break
        end
      end

28
      namespace.sub!(%r{\A/}, '')
29
      project.rstrip!
30
      project.sub!(/\.git\z/, '')
31

32 33 34 35
      if self_url?(url, namespace, project)
        [namespace_project_path(namespace, project),
         namespace_project_tree_path(namespace, project, submodule_item.id)]
      elsif relative_self_url?(url)
36
        relative_self_links(url, submodule_item.id, repository.project)
37 38 39 40 41 42 43
      elsif github_dot_com_url?(url)
        standard_links('github.com', namespace, project, submodule_item.id)
      elsif gitlab_dot_com_url?(url)
        standard_links('gitlab.com', namespace, project, submodule_item.id)
      else
        [sanitize_submodule_url(url), nil]
      end
44
    else
45
      [sanitize_submodule_url(url), nil]
46 47
    end
  end
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
48

49 50 51
  protected

  def github_dot_com_url?(url)
52
    url =~ %r{github\.com[/:][^/]+/[^/]+\Z}
53 54 55
  end

  def gitlab_dot_com_url?(url)
56
    url =~ %r{gitlab\.com[/:][^/]+/[^/]+\Z}
57
  end
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
58

Vinnie Okada's avatar
Vinnie Okada committed
59
  def self_url?(url, namespace, project)
60 61 62
    url_no_dotgit = url.chomp('.git')
    return true if url_no_dotgit == [Gitlab.config.gitlab.url, '/', namespace, '/',
                                     project].join('')
63

64
    url_with_dotgit = url_no_dotgit + '.git'
65
    url_with_dotgit == Gitlab::Shell.new.url_to_repo([namespace, '/', project].join(''))
66
  end
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
67

68
  def relative_self_url?(url)
69
    url.start_with?('../', './')
70 71
  end

Vinnie Okada's avatar
Vinnie Okada committed
72
  def standard_links(host, namespace, project, commit)
73 74
    base = ['https://', host, '/', namespace, '/', project].join('')
    [base, [base, '/tree/', commit].join('')]
75
  end
76

77 78 79 80 81 82 83 84 85 86 87 88 89 90
  def relative_self_links(relative_path, commit, project)
    relative_path.rstrip!
    absolute_project_path = "/" + project.full_path

    # Resolve `relative_path` to target path
    # Assuming `absolute_project_path` is `/g1/p1`:
    # ../p2.git -> /g1/p2
    # ../g2/p3.git -> /g1/g2/p3
    # ../../g3/g4/p4.git -> /g3/g4/p4
    submodule_project_path = File.absolute_path(relative_path, absolute_project_path)
    target_namespace_path = File.dirname(submodule_project_path)

    if target_namespace_path == '/' || target_namespace_path.start_with?(absolute_project_path)
      return [nil, nil]
91
    end
92

93 94 95
    target_namespace_path.sub!(%r{^/}, '')
    submodule_base = File.basename(submodule_project_path, '.git')

96 97
    begin
      [
98 99
        namespace_project_path(target_namespace_path, submodule_base),
        namespace_project_tree_path(target_namespace_path, submodule_base, commit)
100 101 102 103
      ]
    rescue ActionController::UrlGenerationError
      [nil, nil]
    end
104
  end
105 106 107 108 109 110 111 112 113 114 115 116

  def sanitize_submodule_url(url)
    uri = URI.parse(url)

    if uri.scheme.in?(VALID_SUBMODULE_PROTOCOLS)
      uri.to_s
    else
      nil
    end
  rescue URI::InvalidURIError
    nil
  end
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
117
end