repository.rb 6.02 KB
Newer Older
1
class Repository
2 3
  include Gitlab::ShellAdapter

4
  attr_accessor :raw_repository, :path_with_namespace
5

6
  def initialize(path_with_namespace, default_branch = nil)
7
    @path_with_namespace = path_with_namespace
8
    @raw_repository = Gitlab::Git::Repository.new(path_to_repo) if path_with_namespace
9 10 11 12
  rescue Gitlab::Git::Repository::NoRepository
    nil
  end

13 14 15 16
  def path_to_repo
    @path_to_repo ||= File.join(Gitlab.config.gitlab_shell.repos_path, path_with_namespace + ".git")
  end

17 18 19 20 21 22
  def exists?
    raw_repository
  end

  def empty?
    raw_repository.empty?
23 24 25
  end

  def commit(id = nil)
26
    return nil unless raw_repository
27
    commit = Gitlab::Git::Commit.find(raw_repository, id)
28 29 30 31 32
    commit = Commit.new(commit) if commit
    commit
  end

  def commits(ref, path = nil, limit = nil, offset = nil)
33 34 35 36 37 38 39
    commits = Gitlab::Git::Commit.where(
      repo: raw_repository,
      ref: ref,
      path: path,
      limit: limit,
      offset: offset,
    )
40
    commits = Commit.decorate(commits) if commits.present?
41 42 43
    commits
  end

44 45
  def commits_between(from, to)
    commits = Gitlab::Git::Commit.between(raw_repository, from, to)
46
    commits = Commit.decorate(commits) if commits.present?
47 48 49
    commits
  end

50 51 52 53 54 55 56 57
  def find_branch(name)
    branches.find { |branch| branch.name == name }
  end

  def find_tag(name)
    tags.find { |tag| tag.name == name }
  end

58 59 60 61 62 63
  def add_branch(branch_name, ref)
    Rails.cache.delete(cache_key(:branch_names))

    gitlab_shell.add_branch(path_with_namespace, branch_name, ref)
  end

64 65 66 67 68 69
  def add_tag(tag_name, ref)
    Rails.cache.delete(cache_key(:tag_names))

    gitlab_shell.add_tag(path_with_namespace, tag_name, ref)
  end

70
  def rm_branch(branch_name)
71 72
    Rails.cache.delete(cache_key(:branch_names))

73 74 75
    gitlab_shell.rm_branch(path_with_namespace, branch_name)
  end

76
  def rm_tag(tag_name)
77 78
    Rails.cache.delete(cache_key(:tag_names))

79 80 81
    gitlab_shell.rm_tag(path_with_namespace, tag_name)
  end

82 83 84 85 86 87 88 89 90 91 92 93
  def round_commit_count
    if commit_count > 10000
      '10000+'
    elsif commit_count > 5000
      '5000+'
    elsif commit_count > 1000
      '1000+'
    else
      commit_count
    end
  end

94 95 96 97 98 99 100 101 102 103 104 105
  def branch_names
    Rails.cache.fetch(cache_key(:branch_names)) do
      raw_repository.branch_names
    end
  end

  def tag_names
    Rails.cache.fetch(cache_key(:tag_names)) do
      raw_repository.tag_names
    end
  end

106 107
  def commit_count
    Rails.cache.fetch(cache_key(:commit_count)) do
108
      begin
109
        raw_repository.commit_count(self.root_ref)
110 111 112
      rescue
        0
      end
113
    end
114 115
  end

116 117 118 119 120 121 122 123 124 125
  # Return repo size in megabytes
  # Cached in redis
  def size
    Rails.cache.fetch(cache_key(:size)) do
      raw_repository.size
    end
  end

  def expire_cache
    Rails.cache.delete(cache_key(:size))
126 127
    Rails.cache.delete(cache_key(:branch_names))
    Rails.cache.delete(cache_key(:tag_names))
128
    Rails.cache.delete(cache_key(:commit_count))
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
129
    Rails.cache.delete(cache_key(:graph_log))
130
    Rails.cache.delete(cache_key(:readme))
131
    Rails.cache.delete(cache_key(:version))
132
    Rails.cache.delete(cache_key(:contribution_guide))
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
133 134 135
  end

  def graph_log
136
    Rails.cache.fetch(cache_key(:graph_log)) do
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
137 138 139
      stats = Gitlab::Git::GitStats.new(raw, root_ref)
      stats.parsed_log
    end
140 141 142 143 144 145
  end

  def cache_key(type)
    "#{type}:#{path_with_namespace}"
  end

146 147 148 149
  def method_missing(m, *args, &block)
    raw_repository.send(m, *args, &block)
  end

150
  def respond_to?(method)
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
151
    return true if raw_repository.respond_to?(method)
152 153 154

    super
  end
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
155 156 157 158

  def blob_at(sha, path)
    Gitlab::Git::Blob.find(self, sha, path)
  end
159

160 161 162 163
  def blob_by_oid(oid)
    Gitlab::Git::Blob.raw(self, oid)
  end

164 165
  def readme
    Rails.cache.fetch(cache_key(:readme)) do
166
      tree(:head).readme
167 168
    end
  end
169

170 171 172 173 174 175 176 177
  def version
    Rails.cache.fetch(cache_key(:version)) do
      tree(:head).blobs.find do |file|
        file.name.downcase == 'version'
      end
    end
  end

178 179 180 181 182 183
  def contribution_guide
    Rails.cache.fetch(cache_key(:contribution_guide)) do
      tree(:head).contribution_guide
    end
  end

184 185 186 187 188 189 190 191 192 193 194
  def head_commit
    commit(self.root_ref)
  end

  def tree(sha = :head, path = nil)
    if sha == :head
      sha = head_commit.sha
    end

    Tree.new(self, sha, path)
  end
195 196

  def blob_at_branch(branch_name, path)
197
    last_commit = commit(branch_name)
198

199 200 201 202 203
    if last_commit
      blob_at(last_commit.sha, path)
    else
      nil
    end
204
  end
205 206 207 208 209 210 211 212

  # Returns url for submodule
  #
  # Ex.
  #   @repository.submodule_url_for('master', 'rack')
  #   # => git@localhost:rack.git
  #
  def submodule_url_for(ref, path)
213
    if submodules(ref).any?
214 215 216 217 218 219 220
      submodule = submodules(ref)[path]

      if submodule
        submodule['url']
      end
    end
  end
221 222 223 224

  def last_commit_for_path(sha, path)
    commits(sha, path, 1).last
  end
225 226 227 228 229

  # Remove archives older than 2 hours
  def clean_old_archives
    Gitlab::Popen.popen(%W(find #{Gitlab.config.gitlab.repository_downloads_path} -mmin +120 -delete))
  end
230 231 232 233 234 235 236 237 238 239 240 241 242 243 244

  def branches_sorted_by(value)
    case value
    when 'recently_updated'
      branches.sort do |a, b|
        commit(b.target).committed_date <=> commit(a.target).committed_date
      end
    when 'last_updated'
      branches.sort do |a, b|
        commit(a.target).committed_date <=> commit(b.target).committed_date
      end
    else
      branches
    end
  end
245 246 247 248

  def contributors
    log = graph_log.group_by { |i| i[:author_email] }

249 250 251
    log.map do |email, contributions|
      contributor = Gitlab::Contributor.new
      contributor.email = email
252 253

      contributions.each do |contribution|
254 255
        if contributor.name.blank?
          contributor.name = contribution[:author_name]
256 257
        end

258 259 260
        contributor.commits += 1
        contributor.additions += contribution[:additions] || 0
        contributor.deletions += contribution[:deletions] || 0
261 262
      end

263 264
      contributor
    end
265
  end
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281

  def blob_for_diff(commit, diff)
    file = blob_at(commit.id, diff.new_path)

    unless file
      file = prev_blob_for_diff(commit, diff)
    end

    file
  end

  def prev_blob_for_diff(commit, diff)
    if commit.parent_id
      blob_at(commit.parent_id, diff.old_path)
    end
  end
282
end