Class: Gitlab::Git::Blob
- Inherits:
-
Object
- Object
- Gitlab::Git::Blob
- Includes:
- EncodingHelper, Linguist::BlobHelper
- Defined in:
- lib/gitlab_git/blob.rb
Constant Summary collapse
- MAX_DATA_DISPLAY_SIZE =
This number is the maximum amount of data that we want to display to the user. We load as much as we can for encoding detection (Linguist) and LFS pointer parsing. All other cases where we need full blob data should use load_all_data!.
10485760
Constants included from EncodingHelper
EncodingHelper::ENCODING_CONFIDENCE_THRESHOLD
Instance Attribute Summary collapse
-
#binary ⇒ Object
Returns the value of attribute binary.
-
#commit_id ⇒ Object
Returns the value of attribute commit_id.
-
#data ⇒ Object
Returns the value of attribute data.
-
#id ⇒ Object
Returns the value of attribute id.
-
#loaded_size ⇒ Object
Returns the value of attribute loaded_size.
-
#mode ⇒ Object
Returns the value of attribute mode.
-
#name ⇒ Object
Returns the value of attribute name.
-
#path ⇒ Object
Returns the value of attribute path.
-
#size ⇒ Object
Returns the value of attribute size.
Class Method Summary collapse
-
.commit(repository, options, action = :add) ⇒ Object
Commit file in repository and return commit sha.
- .find(repository, sha, path) ⇒ Object
-
.find_entry_by_path(repository, root_id, path) ⇒ Object
Recursive search of blob id by path.
- .raw(repository, sha) ⇒ Object
-
.remove(repository, options) ⇒ Object
Remove file from repository and return commit sha.
-
.rename(repository, options) ⇒ Object
Rename file from repository and return commit sha.
- .submodule_blob(blob_entry, path, sha) ⇒ Object
Instance Method Summary collapse
- #binary? ⇒ Boolean
- #empty? ⇒ Boolean
-
#initialize(options) ⇒ Blob
constructor
A new instance of Blob.
- #lfs_oid ⇒ Object
-
#lfs_pointer? ⇒ Boolean
Valid LFS object pointer is a text file consisting of version oid size see github.com/github/git-lfs/blob/v1.1.0/docs/spec.md#the-pointer.
- #lfs_size ⇒ Object
-
#load_all_data!(repository) ⇒ Object
Load all blob data (not just the first MAX_DATA_DISPLAY_SIZE bytes) into memory as a Ruby string.
- #truncated? ⇒ Boolean
Methods included from EncodingHelper
Constructor Details
#initialize(options) ⇒ Blob
Returns a new instance of Blob.
253 254 255 256 257 258 259 260 261 |
# File 'lib/gitlab_git/blob.rb', line 253 def initialize() %w(id name path size data mode commit_id binary).each do |key| self.send("#{key}=", [key.to_sym]) end @loaded_all_data = false # Retain the actual size before it is encoded @loaded_size = @data.bytesize if @data end |
Instance Attribute Details
#binary ⇒ Object
Returns the value of attribute binary.
16 17 18 |
# File 'lib/gitlab_git/blob.rb', line 16 def binary @binary end |
#commit_id ⇒ Object
Returns the value of attribute commit_id.
16 17 18 |
# File 'lib/gitlab_git/blob.rb', line 16 def commit_id @commit_id end |
#data ⇒ Object
Returns the value of attribute data.
16 17 18 |
# File 'lib/gitlab_git/blob.rb', line 16 def data @data end |
#id ⇒ Object
Returns the value of attribute id.
16 17 18 |
# File 'lib/gitlab_git/blob.rb', line 16 def id @id end |
#loaded_size ⇒ Object
Returns the value of attribute loaded_size.
16 17 18 |
# File 'lib/gitlab_git/blob.rb', line 16 def loaded_size @loaded_size end |
#mode ⇒ Object
Returns the value of attribute mode.
16 17 18 |
# File 'lib/gitlab_git/blob.rb', line 16 def mode @mode end |
#name ⇒ Object
Returns the value of attribute name.
16 17 18 |
# File 'lib/gitlab_git/blob.rb', line 16 def name @name end |
#path ⇒ Object
Returns the value of attribute path.
16 17 18 |
# File 'lib/gitlab_git/blob.rb', line 16 def path @path end |
#size ⇒ Object
Returns the value of attribute size.
16 17 18 |
# File 'lib/gitlab_git/blob.rb', line 16 def size @size end |
Class Method Details
.commit(repository, options, action = :add) ⇒ Object
Commit file in repository and return commit sha
options should contain next structure:
file: {
content: 'Lorem ipsum...',
path: 'documents/story.txt',
update: true
},
author: {
email: '[email protected]',
name: 'Test User',
time: Time.now
},
committer: {
email: '[email protected]',
name: 'Test User',
time: Time.now
},
commit: {
message: 'Wow such commit',
branch: 'master',
update_ref: false
}
124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 |
# File 'lib/gitlab_git/blob.rb', line 124 def commit(repository, , action = :add) file = [:file] update = file[:update].nil? ? true : file[:update] = [:author] committer = [:committer] commit = [:commit] repo = repository.rugged ref = commit[:branch] update_ref = commit[:update_ref].nil? ? true : commit[:update_ref] parents = [] mode = 0o100644 unless ref.start_with?('refs/') ref = 'refs/heads/' + ref end path_name = PathHelper.normalize_path(file[:path]) # Abort if any invalid characters remain (e.g. ../foo) raise Repository::InvalidBlobName.new("Invalid path") if path_name.each_filename.to_a.include?('..') filename = path_name.to_s index = repo.index unless repo.empty? rugged_ref = repo.references[ref] raise Repository::InvalidRef.new("Invalid branch name") unless rugged_ref last_commit = rugged_ref.target index.read_tree(last_commit.tree) parents = [last_commit] end if action == :remove index.remove(filename) else file_entry = index.get(filename) if action == :rename old_path_name = PathHelper.normalize_path(file[:previous_path]) old_filename = old_path_name.to_s file_entry = index.get(old_filename) index.remove(old_filename) unless file_entry.blank? end if file_entry raise Repository::InvalidBlobName.new("Filename already exists; update not allowed") unless update # Preserve the current file mode if one is available mode = file_entry[:mode] if file_entry[:mode] end content = file[:content] detect = CharlockHolmes::EncodingDetector.new.detect(content) if content unless detect && detect[:type] == :binary # When writing to the repo directly as we are doing here, # the `core.autocrlf` config isn't taken into account. content.gsub!("\r\n", "\n") if repository.autocrlf end oid = repo.write(content, :blob) index.add(path: filename, oid: oid, mode: mode) end opts = {} opts[:tree] = index.write_tree(repo) opts[:author] = opts[:committer] = committer opts[:message] = commit[:message] opts[:parents] = parents opts[:update_ref] = ref if update_ref Rugged::Commit.create(repo, opts) end |
.find(repository, sha, path) ⇒ Object
19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
# File 'lib/gitlab_git/blob.rb', line 19 def find(repository, sha, path) commit = repository.lookup(sha) root_tree = commit.tree blob_entry = find_entry_by_path(repository, root_tree.oid, path) return nil unless blob_entry if blob_entry[:type] == :commit submodule_blob(blob_entry, path, sha) else blob = repository.lookup(blob_entry[:oid]) if blob Blob.new( id: blob.oid, name: blob_entry[:name], size: blob.size, data: blob.content(MAX_DATA_DISPLAY_SIZE), mode: blob_entry[:filemode].to_s(8), path: path, commit_id: sha, binary: blob.binary? ) end end end |
.find_entry_by_path(repository, root_id, path) ⇒ Object
Recursive search of blob id by path
Ex.
blog/ # oid: 1a
app/ # oid: 2a
models/ # oid: 3a
file.rb # oid: 4a
Blob.find_entry_by_path(repo, ‘1a’, ‘app/file.rb’) # => ‘4a’
69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 |
# File 'lib/gitlab_git/blob.rb', line 69 def find_entry_by_path(repository, root_id, path) root_tree = repository.lookup(root_id) # Strip leading slashes path[/^\/*/] = '' path_arr = path.split('/') entry = root_tree.find do |entry| entry[:name] == path_arr[0] end return nil unless entry if path_arr.size > 1 return nil unless entry[:type] == :tree path_arr.shift find_entry_by_path(repository, entry[:oid], path_arr.join('/')) else [:blob, :commit].include?(entry[:type]) ? entry : nil end end |
.raw(repository, sha) ⇒ Object
47 48 49 50 51 52 53 54 55 56 |
# File 'lib/gitlab_git/blob.rb', line 47 def raw(repository, sha) blob = repository.lookup(sha) Blob.new( id: blob.oid, size: blob.size, data: blob.content(MAX_DATA_DISPLAY_SIZE), binary: blob.binary? ) end |
.remove(repository, options) ⇒ Object
Remove file from repository and return commit sha
options should contain next structure:
file: {
path: 'documents/story.txt'
},
author: {
email: '[email protected]',
name: 'Test User',
time: Time.now
},
committer: {
email: '[email protected]',
name: 'Test User',
time: Time.now
},
commit: {
message: 'Remove FILENAME',
branch: 'master'
}
219 220 221 |
# File 'lib/gitlab_git/blob.rb', line 219 def remove(repository, ) commit(repository, , :remove) end |
.rename(repository, options) ⇒ Object
Rename file from repository and return commit sha
options should contain next structure:
file: {
previous_path: 'documents/old_story.txt'
path: 'documents/story.txt'
content: 'Lorem ipsum...',
update: true
},
author: {
email: '[email protected]',
name: 'Test User',
time: Time.now
},
committer: {
email: '[email protected]',
name: 'Test User',
time: Time.now
},
commit: {
message: 'Rename FILENAME',
branch: 'master'
}
248 249 250 |
# File 'lib/gitlab_git/blob.rb', line 248 def rename(repository, ) commit(repository, , :rename) end |
Instance Method Details
#binary? ⇒ Boolean
263 264 265 |
# File 'lib/gitlab_git/blob.rb', line 263 def binary? @binary.nil? ? super : @binary == true end |
#empty? ⇒ Boolean
267 268 269 |
# File 'lib/gitlab_git/blob.rb', line 267 def empty? !data || data == '' end |
#lfs_oid ⇒ Object
299 300 301 302 303 304 305 306 |
# File 'lib/gitlab_git/blob.rb', line 299 def lfs_oid if has_lfs_version_key? oid = data.match(/(?<=sha256:)([0-9a-f]{64})/) return oid[1] if oid end nil end |
#lfs_pointer? ⇒ Boolean
Valid LFS object pointer is a text file consisting of version oid size see github.com/github/git-lfs/blob/v1.1.0/docs/spec.md#the-pointer
295 296 297 |
# File 'lib/gitlab_git/blob.rb', line 295 def lfs_pointer? has_lfs_version_key? && lfs_oid.present? && lfs_size.present? end |
#lfs_size ⇒ Object
308 309 310 311 312 313 314 315 |
# File 'lib/gitlab_git/blob.rb', line 308 def lfs_size if has_lfs_version_key? size = data.match(/(?<=size )([0-9]+)/) return size[1] if size end nil end |
#load_all_data!(repository) ⇒ Object
Load all blob data (not just the first MAX_DATA_DISPLAY_SIZE bytes) into memory as a Ruby string.
277 278 279 280 281 282 283 284 |
# File 'lib/gitlab_git/blob.rb', line 277 def load_all_data!(repository) return if @data == '' # don't mess with submodule blobs return @data if @loaded_all_data @loaded_all_data = true @data = repository.lookup(id).content @loaded_size = @data.bytesize end |
#truncated? ⇒ Boolean
317 318 319 |
# File 'lib/gitlab_git/blob.rb', line 317 def truncated? size && (size > loaded_size) end |