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
-
#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
- #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.
249 250 251 252 253 254 255 256 257 |
# File 'lib/gitlab_git/blob.rb', line 249 def initialize() %w(id name path size data mode commit_id).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
#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
}
122 123 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 |
# File 'lib/gitlab_git/blob.rb', line 122 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 = [] 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 if action == :rename old_path_name = PathHelper.normalize_path(file[:previous_path]) old_filename = old_path_name.to_s index.remove(old_filename) end mode = 0o100644 file_entry = index.get(filename) 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 |
# 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, ) 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’
67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 |
# File 'lib/gitlab_git/blob.rb', line 67 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
46 47 48 49 50 51 52 53 54 |
# File 'lib/gitlab_git/blob.rb', line 46 def raw(repository, sha) blob = repository.lookup(sha) Blob.new( id: blob.oid, size: blob.size, data: blob.content(MAX_DATA_DISPLAY_SIZE), ) 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'
}
215 216 217 |
# File 'lib/gitlab_git/blob.rb', line 215 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'
}
244 245 246 |
# File 'lib/gitlab_git/blob.rb', line 244 def rename(repository, ) commit(repository, , :rename) end |
Instance Method Details
#empty? ⇒ Boolean
259 260 261 |
# File 'lib/gitlab_git/blob.rb', line 259 def empty? !data || data == '' end |
#lfs_oid ⇒ Object
291 292 293 294 295 296 297 298 |
# File 'lib/gitlab_git/blob.rb', line 291 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
287 288 289 |
# File 'lib/gitlab_git/blob.rb', line 287 def lfs_pointer? has_lfs_version_key? && lfs_oid.present? && lfs_size.present? end |
#lfs_size ⇒ Object
300 301 302 303 304 305 306 307 |
# File 'lib/gitlab_git/blob.rb', line 300 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.
269 270 271 272 273 274 275 276 |
# File 'lib/gitlab_git/blob.rb', line 269 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
309 310 311 |
# File 'lib/gitlab_git/blob.rb', line 309 def truncated? size && (size > loaded_size) end |